TairSearch是Tair全自研的全文搜索数据结构,采用和Elasticsearch相似(ES-LIKE)的查询语法。
TairSearch简介
TairSearch具有如下主要特点:
低延迟、高性能:依托Tair的超高性能计算能力,提供毫秒级别的写入和全文搜索能力,更多信息请参见TairSearch性能白皮书。
增量、局部更新:支持文档的增量更新与局部索引更新,包括追加字段、更新字段、删除字段以及字段自增等。
语法灵活:支持更加灵活、可读性更强的JSON查询语法,提供Bool、Match、Term、分页等查询功能,语法与Elasticsearch类似,同时支持自定义排序。
聚合查询:支持Terms、Metrics、Filter等聚合算子,更多信息请参见Aggregations介绍。
Auto-complete Suggestion:支持前缀模糊搜索、自动补全等功能。
分词定制:提供丰富、强大的分词器,内置英文(Standard、Stop等)、中文(Jieba、IK)及世界主要语言分词器,同时支持Custom自定义分词器,允许自定义用户词典和停用词等,更多信息请参见Search分词器。
索引分片查询:支持使用TFT.MSEARCH命令同时对多个索引分片(Shard index)进行查询,并自动返回已聚合的结果集。
压缩存储:支持文档级别的压缩存储(默认未开启),从而节省内存占用空间。
查询缓存:支持将最近的查询结果(可自定义)存储在缓存,从而提高热点数据的查询效率。
发布记录
内存型(兼容Redis 5.0)
2022年03月11日发布1.7.27版本,首次发布TairSearch。
2022年05月24日发布1.8.5版本,支持TairSearch Aggregations(聚合)功能。
2022年09月06日发布5.0.15版本,支持TFT.MSEARCH功能。
2023年01月13日发布5.0.25版本,全面支持分词器框架。
2023年03月15日发布5.0.28版本,支持查询缓存,支持文档压缩存储,新增TFT.ANALYZER命令。
2023年06月12日发布5.0.35版本,支持数组类型的文档,支持Okapi BM25算法。
内存型(兼容Redis 6.0)
2023年02月07日发布6.2.4.1版本,首次支持TairSearch。
该版本能力对齐内存型(兼容Redis 5.0)的5.0.25版本。
2023年03月14日发布6.2.5.0版本,支持查询缓存,支持文档压缩存储,新增TFT.ANALYZER命令。
该版本能力对齐内存型(兼容Redis 5.0)的5.0.28版本。
2023年06月12日发布6.2.7.3版本,支持数组类型的文档,支持Okapi BM25算法。
该版本能力对齐内存型(兼容Redis 5.0)的5.0.35版本。
2023年12月21日发布23.12.1.2版本,支持TFT.EXPLAINSCORE命令。
最佳实践
前提条件
最新小版本将提供更丰富的功能与稳定的服务,建议将实例的小版本升级到最新,具体操作请参见升级小版本。如果您的实例为集群实例或读写分离架构,请将代理节点的小版本也升级到最新,否则可能出现命令无法识别的情况。
注意事项
操作对象为Tair实例中的TairSearch数据。
为节省内存,推荐使用如下方法:
创建索引(index)时请将文档中需要创建(反向)索引的字段设置为索引字段(将字段的index设置为true),其余字段的index设置为false。
使用_source参数中的include与exclude机制剔除源文档中不需要的字段(field),保存需要的信息。
若文档需要进行分词处理,请选择合适的分词器,避免不合适的分词器拆成出过多、无用的Token(词元),增加内存开销。
若文档较大,您可以合理使用文档压缩功能对文档进行透明压缩(自动压缩、解压)。
避免在单个索引中插入过多的文档,建议将文档存入多个不同的索引中,并控制单个索引的文档数在500万以下,从而规避(集群)实例发生数据倾斜,均衡读写流量,避免造成大Key与热key。
命令列表
表 1. 全文检索命令
命令 | 语法 | 说明 |
| 创建索引(index)并添加映射(mappings),映射语法类似ES语法。在添加索引文档前,必须先创建索引。 | |
| 向指定的索引中新增properties字段,或修改索引设置。 | |
| 获取索引的映射内容。 | |
| 向索引中插入一个文档(document),可通过WITH_ID指定该文档在索引内的唯一ID(doc_id),若doc_id已存在,则更新并覆盖原文档。若不指定WITH_ID(默认),则自动生成doc_id。 | |
| 向索引中插入多个文档(document),每个文档必须指定文档ID(doc_id)。若某个文档写入失败(例如写入的文档内容与定义的格式不符),则该命令的所有文档均不会写入。 | |
| 更新索引中doc_id指定的文档,若更新的字段为mapping指定的索引字段时,该字段更新的内容需与mapping指定的类型一致;若非索引字段,支持更新任意字段类型的内容。 说明 若更新的字段已存在,则更新原文档,若字段不存在,则新增该字段。若指定的文档不存在,该命令支持自动创建文档,此时效果等同于TFT.ADDDOC。 | |
| 删除索引中doc_id指定文档的指定字段,若该字段为索引字段,会同时在索引中删除该字段的信息。 说明 若指定的字段不存在(例如被_source过滤的字段),则操作失败。 | |
| 向索引中doc_id指定文档的指定字段增加整数值(increment),支持指定increment为负数,支持指定的字段类型为long或int类型。 说明 若指定的文档不存在,该命令支持自动创建文档,初始化字段的值为0,并增加指定的increment。若指定的字段不存在(例如被_source过滤的字段),则操作失败。 | |
| 向索引中doc_id指定文档的指定字段增加浮点数值(increment),支持指定increment为负数,支持指定的字段类型为double类型。 说明 若指定的文档不存在,该命令支持自动创建文档,初始化字段的值为0,并增加指定的increment。若指定的字段不存在(例如被_source过滤的字段),则操作失败。 | |
| 获取索引中指定doc_id的文档内容。 | |
| 查询索引中指定doc_id的文档是否存在。 | |
| 获取索引中的文档数量。 | |
| 获取索引中所有的doc_id。 | |
| 删除索引中doc_id指定的文档,支持指定多个doc_id。 | |
| 删除索引中所有文档,但不会删除index。 | |
| 查询分词器分词效果。 | |
| 根据query语句搜索索引的文档,query语法类似ES语法。 | |
| 根据query语句搜索多个索引的文档(待查询索引的mappings和settings的配置必须相同),汇聚多个索引的查询结果,再次进行打分、排序、聚合并返回。 | |
| 查询query语句的执行耗时,返回内容包括查询过程中涉及到的文档集合数及各阶段的耗时。 | |
| 查询执行query语句的计分详情信息,您可以通过该命令了解文档分数的计算过程,并优化Search语句,提升文档的查询效果。 | |
| 使用原生Redis的DEL命令可以删除一条或多条TairSearch数据。 |
表 2. 自动补齐命令
命令 | 语法 | 说明 |
| 在指定索引中,添加自动补全的文本及对应权重,支持添加多个文本。 | |
| 在指定索引中,删除自动补全的文本,支持删除多个文本。 | |
| 获取指定索引中自动补全文本的数量。 | |
| 根据指定前缀,查询匹配的自动补全文本,将优先返回权重比较高的text。 | |
| 获取指定索引的全量自动补全文本。 |
本文的命令语法定义如下:
大写关键字
:命令关键字。斜体
:变量。[options]
:可选参数,不在括号中的参数为必选。A|B
:该组参数互斥,请进行二选一或多选一。...
:前面的内容可重复。
TFT.CREATEINDEX
类别 | 说明 |
语法 |
|
命令描述 | 创建索引(index)并添加映射(mappings),映射语法类似ES语法。在添加索引文档前,必须先创建索引。 说明 为避免产生大Key,您可以预先将大索引拆分成小索引,并设计负载规则将数据写入不同的索引中。创建该类索引时,必须使该类索引具备相同的mappings和settings配置,创建后可通过TFT.MSEARCH进行查询。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.UPDATEINDEX
类别 | 说明 |
语法 |
|
命令描述 | 向指定的索引中新增properties字段,或修改索引设置。 |
选项 |
说明 mappings和settings的语法请参见TFT.CREATEINDEX。 |
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.GETINDEX
类别 | 说明 |
语法 |
|
命令描述 | 获取索引的映射内容。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.ADDDOC
类别 | 说明 |
语法 |
|
命令描述 | 向索引中插入一个文档(document),可通过WITH_ID指定该文档在索引内的唯一ID(doc_id),若doc_id已存在,则更新并覆盖原文档。若不指定WITH_ID(默认),则自动生成doc_id。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
数组的添加示例:
|
TFT.MADDDOC
类别 | 说明 |
语法 |
|
命令描述 | 向索引中插入多个文档(document),每个文档必须指定文档ID(doc_id)。若某个文档写入失败(例如写入的文档内容与定义的格式不符),则该命令的所有文档均不会写入。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.UPDATEDOCFIELD
类别 | 说明 |
语法 |
|
命令描述 | 更新索引中doc_id指定的文档,若更新的字段为mapping指定的索引字段时,该字段更新的内容需与mapping指定的类型一致;若非索引字段,支持更新任意字段类型的内容。 说明 若更新的字段已存在,则更新原文档,若字段不存在,则新增该字段。若指定的文档不存在,该命令支持自动创建文档,此时效果等同于TFT.ADDDOC。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.DELDOCFIELD
类别 | 说明 |
语法 |
|
命令描述 | 删除索引中doc_id指定文档的指定字段,若该字段为索引字段,会同时在索引中删除该字段的信息。 说明 若指定的字段不存在(例如被_source过滤的字段),则操作失败。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.INCRLONGDOCFIELD
类别 | 说明 |
语法 |
|
命令描述 | 向索引中doc_id指定文档的指定字段增加整数值(increment),支持指定increment为负数,支持指定的字段类型为long或int类型。 说明 若指定的文档不存在,该命令支持自动创建文档,初始化字段的值为0,并增加指定的increment。若指定的字段不存在(例如被_source过滤的字段),则操作失败。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.INCRFLOATDOCFIELD
类别 | 说明 |
语法 |
|
命令描述 | 向索引中doc_id指定文档的指定字段增加浮点数值(increment),支持指定increment为负数,支持指定的字段类型为double类型。 说明 若指定的文档不存在,该命令支持自动创建文档,初始化字段的值为0,并增加指定的increment。若指定的字段不存在(例如被_source过滤的字段),则操作失败。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.GETDOC
类别 | 说明 |
语法 |
|
命令描述 | 获取索引中指定doc_id的文档内容。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.EXISTS
类别 | 说明 |
语法 |
|
命令描述 | 查询索引中指定doc_id的文档是否存在。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.DOCNUM
类别 | 说明 |
语法 |
|
命令描述 | 获取索引中的文档数量。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.SCANDOCID
类别 | 说明 |
语法 |
|
命令描述 | 获取索引中所有的doc_id。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.DELDOC
类别 | 说明 |
语法 |
|
命令描述 | 删除索引中doc_id指定的文档,支持指定多个doc_id。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.DELALL
类别 | 说明 |
语法 |
|
命令描述 | 删除索引中所有文档,但不会删除index。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.ANALYZER
类别 | 说明 |
语法 |
|
命令描述 | 查询分词器分词效果。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.SEARCH
类别 | 说明 |
语法 |
|
命令描述 | 根据query语句搜索索引的文档,query语法类似ES语法。 |
选项 | index为待查询的索引名称;query为类似ES语法的DLS语句,支持如下字段:
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.MSEARCH
类别 | 说明 |
语法 |
|
命令描述 | 根据query语句搜索多个索引的文档(待查询索引的mappings和settings的配置必须相同),汇聚多个索引的查询结果,再次进行打分、排序、聚合并返回。 说明 TFT.MSEARCH命令返回的结果是对多个索引的查询结果再次进行打分、排序、聚合的结果,该结果不等同于对多个索引的数据集合直接进行打分、排序、聚合等结果。TFT.MSEARCH的策略如下:
|
选项 |
说明 相比较TFT.SEARCH的query语句,TFT.MSEARCH的query不支持from参数,但可以通过size、reply_with_keys_cursor与keys_cursor参数实现分页查询,其余参数语法均可参见TFT.SEARCH。 |
返回值 |
|
示例 | 提前执行如下命令:
命令示例:
返回示例:
第二页查询命令示例:
返回示例:
|
TFT.EXPLAINCOST
类别 | 说明 |
语法 |
|
命令描述 | 查询query语句的执行耗时,返回内容包括查询过程中涉及到的文档集合数及各阶段的耗时。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.EXPLAINSCORE
类别 | 说明 |
语法 |
|
命令描述 | 查询执行query语句的计分详情信息,您可以通过该命令了解文档分数的计算过程,并优化Search语句,提升文档的查询效果。 该命令当前仅内存型(兼容Redis 6.0)支持。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.ADDSUG
类别 | 说明 |
语法 |
|
命令描述 | 在指定索引中,添加自动补全的文本及对应权重,支持添加多个文本。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.DELSUG
类别 | 说明 |
语法 |
|
命令描述 | 在指定索引中,删除自动补全的文本,支持删除多个文本。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.SUGNUM
类别 | 说明 |
语法 |
|
命令描述 | 获取指定索引中自动补全文本的数量。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.GETSUG
类别 | 说明 |
语法 |
|
命令描述 | 根据指定前缀,查询匹配的自动补全文本,将优先返回权重比较高的text。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
TFT.GETALLSUGS
类别 | 说明 |
语法 |
|
命令描述 | 获取指定索引的全量自动补全文本。 |
选项 |
|
返回值 |
|
示例 | 命令示例:
返回示例:
|
Aggregations介绍
您可以在TFT.SEARCH请求中添加aggs(或aggregations)子句,对query查询子句的结果进行聚合。
用法
通常情况下,在aggs子句中,您需要自定义聚合名称,并指定聚合类型与聚合字段(field),仅支持聚合数值类型与keyword类型的字段,例如:
TFT.SEARCH shares '{"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Sum":{"sum":{"field":"purchase_price"}}}}'
# 自定义聚合名称为Jay_Sum、聚合类型为sum(求和)、聚合字段为purchase_price。
返回结果包含query的查询结果和aggs的聚合结果:
{"hits":{"hits":[{"_id":"16581351808123930","_index":"today_shares0718","_score":1.0,"_source":{"shares_name":"XAX","logictime":14300210,"purchase_type":1,"purchase_price":101.1,"purchase_count":100,"investor":"Jay"}},{"_id":"16581351809626430","_index":"today_shares0718","_score":1.0,"_source":{"shares_name":"XAX","logictime":14300310,"purchase_type":1,"purchase_price":111.1,"purchase_count":100,"investor":"Jay"}}],"max_score":1.0,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Sum":{"value":212.2}}}
您可以在查询语句中加上"size":0
,将仅返回aggs的结果。
aggs聚合类型
aggs支持Metric Aggregation、Terms Aggregation、Filter Aggregation功能。
类别 | 说明 |
Metric(指标) Aggregation | 一般是对数值类型(例如integer、double等)字段进行数值计算或统计,不支持嵌套子聚合。支持如下指标:
说明 除value_count外,其余指标均只支持数值类型字段。 返回结果:指定字段进行计算后的值,类型均为double。 |
Terms Aggregation | 统计value的去重个数,仅支持keyword类型字段,支持嵌套子聚合,参数说明如下:
部分请求示例:
返回结果:聚合名称为key,类型为Object的JSON内容。Object中以buckets为数组key,数组中的value为对应key和doc_count统计结果。示例如下:
|
Filter Aggregation | filter中可输入query语句,对query查询结果进行再次过滤,支持嵌套子聚合。 返回结果:符合过滤条件的文档个数(doc_count)。 |
Aggregations查询示例
创建索引。
TFT.CREATEINDEX today_shares '{"mappings":{"properties":{"shares_name":{"type":"keyword"},"logictime":{"type":"long"},"purchase_type":{"type":"integer"},"purchase_price":{"type":"double"},"purchase_count":{"type":"long"},"investor":{"type":"keyword"}}}}' # 创建今日股票交易量索引 # shares_name:股票名称 # logictime:成交时间点 # purchase_type:购买类型 # purchase_price:成交价格 # purchase_count:成交数 # investor:投资者ID
预计输出:
OK
添加文档数据。
依次执行如下命令。
TFT.ADDDOC today_shares '{"shares_name":"XAX","logictime":14300210, "purchase_type":1,"purchase_price":101.1, "purchase_count":100,"investor":"Jay"}' TFT.ADDDOC today_shares '{"shares_name":"XAX","logictime":14300310, "purchase_type":1,"purchase_price":111.1, "purchase_count":100,"investor":"Jay"}' TFT.ADDDOC today_shares '{"shares_name":"YBY","logictime":14300410, "purchase_type":1,"purchase_price":11.1, "purchase_count":100,"investor":"Mila"}'
预计输出:
OK
进行查询。
查询示例如下:
sum
# 查询Jay购买股票的总金额。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Sum":{"sum":{"field":"purchase_price"}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Sum":{"value":212.2}}}
max
# 查询Jay购买单只股票的最大金额。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Max":{"max":{"field":"purchase_price"}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Max":{"value":111.1}}}
avg
# 查询Jay购买不同股票的平均金额。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Avg":{"avg":{"field":"purchase_price"}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Avg":{"value":106.1}}}
std_deviation
# 查询Jay购买股票金额的标准差。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Std_Deviation":{"std_deviation":{"field":"purchase_price"}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Std_Deviation":{"value":5.0}}}
extended_stats
# 查询Jay购买股票的整体行情(各指标值)。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Extended_Stats":{"extended_stats":{"field":"purchase_price"}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Extended_Stats":{"count":2,"sum":212.2,"max":111.1,"min":101.1,"avg":106.1,"sum_of_squares":10221.21,"variance":25.0,"std_deviation":5.0}}}
terms
# 统计交易2笔以上的投资者。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}},"aggs":{"Per_Investor_Freq":{"terms":{"field":"investor","min_doc_count":2,"order": {"_key":"desc"}}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Per_Investor_Freq":{"buckets":[{"key":"Jay","doc_count":2}]}}}
terms嵌套
# 统计各股票的交易记录总数以及每种股票的平均成交额,但不包含“XAX”股票。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}},"aggs":{"Per_Investor_Freq":{"terms":{"field":"shares_name","include":"[A-Z]+","exclude":["XAX"]},"aggs":{"Price_Avg":{"avg":{"field":"purchase_price"}}}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Per_Investor_Freq":{"buckets":[{"key":"YBY","doc_count":1,"Price_Avg":{"value":11.1}}]}}}
filter嵌套
# 统计Jay购买股票的数量与整体行情(各指标值)。 TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}}, "aggs":{"Jay_BuyIn_Filter": {"filter": {"term":{"investor": "Jay"}},"aggs":{"Jay_BuyIn_Quatation":{"extended_stats":{"field":"purchase_price"}}}}}}' # 预期输出: {"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Jay_BuyIn_Filter":{"doc_count":2,"Jay_BuyIn_Quatation":{"count":2,"sum":212.2,"max":111.1,"min":101.1,"avg":106.1,"sum_of_squares":10221.21,"variance":25.0,"std_deviation":5.0}}}}