在TairSearch中使用Msearch實現(xiàn)索引分片搜索
TairSearch是Tair全自研的全文搜索數(shù)據(jù)結(jié)構,采用和Elasticsearch相似的查詢語法。本文介紹如何在TairSearch中使用TFT.MSEARCH命令,實現(xiàn)索引分片查詢。
背景信息
在TairSearch數(shù)據(jù)結(jié)構中,Key為路由的最小單位。一個Key通常對應一個Schema(元數(shù)據(jù),由mappings和settings組成),若單個Key添加了過多文檔,則會使該Key成為大Key(BigKey),嚴重時會因該Key占用的內(nèi)存超過單節(jié)點的內(nèi)存限制而導致內(nèi)存溢出(Out Of Memory)。
當單節(jié)點架構的緩存服務的內(nèi)存容量受限時,通常采用如下方法進行擴容:
將單節(jié)點架構實例變配為集群架構實例。
將大Key拆分成多個小Key,并分散到集群架構實例的各個分片中。
TairSearch根據(jù)該原理實現(xiàn)了大Key的內(nèi)存搜索方案:預先將大Key拆分成小Key,設計負載規(guī)則將數(shù)據(jù)寫入不同的Key中,并通過TFT.MSEARCH對該類Key進行查詢。創(chuàng)建該類Key時,必須使該類Key具備相同的Schema配置。更多關于TairSearch的信息,請參見Search。
推薦在集群架構代理模式或讀寫分離架構下使用Msearch功能,結(jié)合TairProxy組件可提升大數(shù)據(jù)場景下的查詢性能。標準架構與集群架構直連模式也能使用Msearch功能,但由于其架構沒有TairProxy組件,無法發(fā)揮該功能的特點,不推薦使用。
Msearch原理
TairSearch提供的TFT.SEARCH命令支持查詢單個Key,提供的TFT.MSEARCH命令支持對Schema配置相同的多個Key進行查詢。
當客戶端發(fā)送寫請求給TairProxy后,TairProxy會根據(jù)Slot將Key寫入對應的數(shù)據(jù)分片節(jié)點中。
Msearch功能要求多個Key的Schema配置必須相同,且拆分多Key的邏輯由您進行決策,您需要了解并控制拆分Key的索引分片規(guī)則。
當客戶端發(fā)送讀請求(TFT.MSEARCH)給TairProxy后,TairProxy會將請求分發(fā)給各個對應的數(shù)據(jù)分片節(jié)點,數(shù)據(jù)分片節(jié)點會完成各個Key的查詢與首次匯總,并將結(jié)果集返回給TairProxy,此時,TairProxy會對所有結(jié)果集進行二次打分、排序、聚合并返回最終的結(jié)果集給客戶端。
Msearch分頁
由于涉及到深度搜索,可能會返回大量結(jié)果集,因此,您可以使用分頁功能分批獲取結(jié)果集。
分頁原理
TFT.MSEARCH的分頁功能不同于TFT.SEARCH提供的from和size組合,是通過指定查詢返回的文檔總數(shù)量(size)和返回各Key下一輪查詢的游標信息(keys_cursor)實現(xiàn)多個Key的分頁查詢。
TFT.MSEARCH的分頁實現(xiàn)過程如下:
在您指定了size后,TFT.MSEARCH命令會對每個Key獲取size個結(jié)果集。
Tair會對匯總結(jié)果進行二次打分、排序、聚合,最終返回size個結(jié)果集,并返回各個Key下一輪查詢的keys_cursor(您需指定
reply_with_keys_cursor
參數(shù)為true
)。說明keys_cursor默認為0,表示第一位。
在下次查詢時,可指定上述返回的keys_cursor信息,Tair將會從各Key指定的位置之后獲取size個結(jié)果集,并重復上述步驟。
分頁示例
例如設置size為10,查詢3個Key(key0
、key1
、key2
)。
Tair會對key0
、key1
、key2
分別獲取10個結(jié)果集(此時共有30個候選文檔),對匯總結(jié)果進行二次打分、排序、聚合,輸出整體排名靠前的10個結(jié)果集,返回的keys_cursor示例為{"keys_cursor":{"key0":2,"key1":5,"key2":3}}
,表示當前10個結(jié)果集的組成為:key0
的前2個、key1
的前5個和key2
的前3個。在下次查詢時指定{"keys_cursor":{"key0":2,"key1":5,"key2":3}}
,Tair將從key0
的第3位開始向后獲取10個文檔,key1
與key2
也類似。
操作樣例
本示例以模擬熱點信息搜索進行Msearch實踐介紹。
假設每天會產(chǎn)生100萬條熱點信息,可以設計1個Key存儲一周的熱點信息,則每個Key預計存儲700萬個文檔數(shù)。
假設模擬場景為保留2周的熱點信息,新周期的信息可以新建Key,達到過期時間則刪除Key。
每條熱點信息具有時間屬性(datetime)、作者(author)、作者ID(uid)以及信息內(nèi)容(content)。
創(chuàng)建索引。
# 創(chuàng)建2個Key,每個Key以“FLOW_年月開始日_結(jié)束日”為命名規(guī)則,需確保不同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" } } } }'
添加文檔數(shù)據(jù)。
# 此處分別向每周的Key寫入一條數(shù)據(jù)為例。 TFT.ADDDOC FLOW_20230109_15 '{ "datetime":20230109001209340, "author":"熱點影視", "uid":7884455, "content":"電影在大年初一就要與觀眾見面了" }' TFT.ADDDOC FLOW_20230116_23 '{ "datetime":20230118011304250, "author":"熱點時尚", "uid":100093, "content":"推出品牌2023兔年生肖系列新品" }'
查詢示例。
搜索2周以來“生肖兔”相關的熱點信息,結(jié)果集按時間排序。
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 } } }