2

如何实现 SQL 用户标签的查询?

 2 years ago
source link: https://forrestsu.github.io/posts/database/sql-user-tags/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何实现 SQL 用户标签的查询?

2021年9月15日
| 字数 1199

1 Preface

在社交 APP 中,经常会看到用户标签功能,那么这个功能如何实现呢? 如微信的用户标签。

考虑两种情况:

  1. 标签的量级较大,我们需要基于 ES 来加速查询;
  2. 标签量级较小,可以使用数据库实现一个简易版的标签功能;

下面我们使用数据库,实现一个简易的标签功能;

2 需求分析

以上面的截图为例,标签需要支持多选,那么问题的核心是:怎么支持指定标签组过滤
先理清这些标签之间的关系:同一行的标签之间是或关系,多行之间是与关系
那么,这里想要直接通过拼接 sql 实现,就比较复杂了。那就尝试在内存中分步实现。

3 实现思路

3.1 思路一

  1. 从用户和标签关联表中, 查询每个用户的 标签ID列表<userid, [tag_id1, tag_id2…]>;
  2. 循环检查 cids 每个ID group; (组之间是与关系, 组内是或关系)
  3. 找出所有满足条件的 user_ids;

3.2 思路二

根据传入的标签, 查询这些标签下的所有用户 (按category_id 排序)

  1. 然后按 category_id 分组,对同一组的 user_id 合并+去重 (或关系);
    注意点: (要核对分组数量, 因为有的分组可能没有用户)
  2. 把多个 category_id 分组,对 user_id 计算交集(与关系)
  3. 把合法的 userID 当做查询条件,查询即可

4 核心代码实现

import "github.com/scylladb/go-set/uset"
// doMapReduce 获取符合条件的 UserIDs 列表
// 按 category_id 分组,然后计算所有分组的交集
func doMapReduce(records []vo.UserTag, categoryCount int) []uint {
	if len(records) <= 0 {
		return nil
	}
	// 1 把同一category_id 下的 userID, 合并+去重
	var prevID = records[0].CategoryTagID
	var current = uset.NewWithSize(100)
	var sets = []*uset.Set{current}
	for _, row := range records {
		if row.CategoryTagID == prevID {
			current.Add(row.UserID)
		} else {
			// new set
			prevID = row.CategoryTagID
			current = uset.New(row.UserID)
			sets = append(sets, current)
		}
	}
	// 2 集合个数, 应该等于请求的标签类别个数
	if len(sets) != categoryCount {
		return nil
	}
	// 3 计算交集,返回列表
	return uset.Intersection(sets...).List()
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK