在TairSearch中使用Msearch实现索引分片搜索

TairSearch是Tair全自研的全文搜索数据结构,采用和Elasticsearch相似的查询语法。本文介绍如何在TairSearch中使用TFT.MSEARCH命令,实现索引分片查询。

背景信息

在TairSearch数据结构中,Key为路由的最小单位。一个Key通常对应一个Schema(元数据,由mappingssettings组成),若单个Key添加了过多文档,则会使该Key成为大Key(BigKey),严重时会因该Key占用的内存超过单节点的内存限制而导致内存溢出(Out Of Memory)。

当单节点架构的缓存服务的内存容量受限时,通常采用如下方法进行扩容:

  1. 将单节点架构实例变配为集群架构实例。

  2. 将大Key拆分成多个小Key,并分散到集群架构实例的各个分片中。

TairSearch根据该原理实现了大Key的内存搜索方案:预先将大Key拆分成小Key,设计负载规则将数据写入不同的Key中,并通过TFT.MSEARCH对该类Key进行查询。创建该类Key时,必须使该类Key具备相同的Schema配置。更多关于TairSearch的信息,请参见Search

推荐在集群架构(代理模式)或读写分离架构下使用Msearch功能,结合TairProxy组件可提升大数据场景下的查询性能。标准架构与集群架构直连模式也能使用Msearch功能,但由于其架构没有TairProxy组件,无法发挥该功能的特点,不推荐使用。

Msearch原理

TairSearch提供的TFT.SEARCH命令支持查询单个Key,提供的TFT.MSEARCH命令支持对Schema配置相同的多个Key进行查询。

当客户端发送写请求给TairProxy后,TairProxy会根据Slot将Key写入对应的数据分片节点中。

重要

Msearch功能要求多个Key的Schema配置必须相同,且拆分多Key的逻辑由您进行决策,您需要了解并控制拆分Key的索引分片规则。

图 1. TairSearch数据在TairProxy架构的写入流程TairProxy数据写入流程

当客户端发送读请求(TFT.MSEARCH)给TairProxy后,TairProxy会将请求分发给各个对应的数据分片节点,数据分片节点会完成各个Key的查询与首次汇总,并将结果集返回给TairProxy,此时,TairProxy会对所有结果集进行二次打分、排序、聚合并返回最终的结果集给客户端。

图 2. TairSearch数据在TairProxy架构的读取(TFT.MSEARCH)流程Msearch读取

Msearch分页

由于涉及到深度搜索,可能会返回大量结果集,因此,您可以使用分页功能分批获取结果集。

分页原理

TFT.MSEARCH的分页功能不同于TFT.SEARCH提供的fromsize组合,是通过指定查询返回的文档总数量(size)和返回各Key下一轮查询的游标信息(keys_cursor)实现多个Key的分页查询。

TFT.MSEARCH的分页实现过程如下:

  1. 在您指定了size后,TFT.MSEARCH命令会对每个Key获取size个结果集。

  2. Tair会对汇总结果进行二次打分、排序、聚合,最终返回size个结果集,并返回各个Key下一轮查询的keys_cursor(您需指定reply_with_keys_cursor参数为true)。

    说明

    keys_cursor默认为0,表示第一位。

  3. 在下次查询时,可指定上述返回的keys_cursor信息,Tair将会从各Key指定的位置之后获取size个结果集,并重复上述步骤。

分页示例

例如设置size为10,查询3个Key(key0key1key2)。

Tair会对key0key1key2分别获取10个结果集(此时共有30个候选文档),对汇总结果进行二次打分、排序、聚合,输出整体排名靠前的10个结果集,返回的keys_cursor示例为{"keys_cursor":{"key0":2,"key1":5,"key2":3}},表示当前10个结果集的组成为:key0的前2个、key1的前5个和key2的前3个。在下次查询时指定{"keys_cursor":{"key0":2,"key1":5,"key2":3}},Tair将从key0的第3位开始向后获取10个文档,key1key2也类似。

操作样例

本示例以模拟热点信息搜索进行Msearch实践介绍。

  • 假设每天会产生100万条热点信息,可以设计1个Key存储一周的热点信息,则每个Key预计存储700万个文档数。

  • 假设模拟场景为保留2周的热点信息,新周期的信息可以新建Key,达到过期时间则删除Key。

  • 每条热点信息具有时间属性(datetime)、作者(author)、作者ID(uid)以及信息内容(content)。

  1. 创建索引。

    # 创建2个Key,每个Key以“FLOW_年月开始日_结束日”为命名规则,需确保不同Key具有相同的Schema配置。
    
    TFT.CREATEINDEX FLOW_20230109_15 '{
        "mappings":{
            "properties":{
                "datetime":{
                    "type":"long"
                },
                "author":{
                    "type":"text"
                },
                "uid":{
                    "type":"long"
                },
                "content":{
                    "type":"text",
                    "analyzer": "jieba"
                }
            }
        }
    }'
    
    TFT.CREATEINDEX FLOW_20230116_23 '{
        "mappings":{
            "properties":{
                "datetime":{
                    "type":"long"
                },
                "author":{
                    "type":"text"
                },
                "uid":{
                    "type":"long"
                },
                "content":{
                    "type":"text",
                    "analyzer": "jieba"
                }
            }
        }
    }'
  2. 添加文档数据。

    # 此处分别向每周的Key写入一条数据为例。
    
    TFT.ADDDOC FLOW_20230109_15 '{
        "datetime":20230109001209340,
        "author":"热点影视",
        "uid":7884455,
        "content":"电影在大年初一就要与观众见面了"
    }'
    
    TFT.ADDDOC FLOW_20230116_23 '{
        "datetime":20230118011304250,
        "author":"热点时尚",
        "uid":100093,
        "content":"推出品牌2023兔年生肖系列新品"
    }'
  3. 查询示例。

    搜索2周以来“生肖兔”相关的热点信息,结果集按时间排序。

    TFT.MSEARCH 2  FLOW_20230109_15 FLOW_20230116_23 '{
        "query":{
            "match":{
                "content":"生肖兔"
            }
        },
        "sort" : [
            { "datetime": { "order" : "desc" }  }
        ],
        "size":10,
        "reply_with_keys_cursor":true,
        "keys_cursor":{
            "FLOW_2023010916":0,
            "FLOW_202301623":0
        }
    }'

    预计输出:

       {
        "hits":{
            "hits":[
                {
                    "_id":"20230118011304250",
                    "_index":"FLOW_20230116_23",
                    "_score":1,
                    "_source":{
                        "datetime":20230118011304250,
                        "author":"热点时尚",
                        "uid":100093,
                        "content":"推出品牌2023兔年生肖系列新品"
                    }
                }
            ],
            "max_score":1,
            "total":{
                "relation":"eq",
                "value":1
            }
        },
        "aux_info":{
            "index_crc64":14159192555612760957,
            "keys_cursor":{
                "FLOW_20230109_15":0,
                "FLOW_20230116_23":1
            }
        }
    }