背景
訂單系統在各行各業中廣泛應用,為消費者、商家背景、促銷系統等第三方提供使用者、産品、訂單等多元度的管理和查詢服務。
為了挖掘出海量訂單資料的潛能,豐富高效的查詢必不可少。然而很多時候并不能給出完整準确的查詢關鍵字,例如,隻知道收貨人姓氏,或是産品名稱部分關鍵字,或是根據收貨人手機尾号找到訂單,我們将這類查詢歸為“模糊查詢”。
需求分析
訂單系統,作為電商系統的“核心”,管理着訂單狀态、商品資訊、使用者資訊、收貨位址和支付資訊,關聯庫存更新,為下遊的倉庫物流系統提供依據。在訂單表設計時,需要記錄上述所有資訊。本文僅以海量訂單管理查詢為背景,摘選部分重要字段,管窺多元索引(SearchIndex)在模糊查詢時的一些典型使用,整理如下:
-
手機号字首比對
覆寫SQL like語義,滿足字首比對、字尾比對和通配符比對查詢。
-
産品名稱模糊查詢
使用者輸入産品名稱中部分關鍵字即可查出包含相關産品的訂單。
-
商品型号的實時查詢提示
隻輸入少量查詢關鍵字就可召回盡可能多的比對結果,可用于“電影名稱”、“産品型号”等字段的實時查詢提示。
傳統解法
MySql和PostgreSQL等關系型DB支援like文法進行模糊查詢,其本質就是用查詢關鍵詞去掃描并比對每條記錄的字元串内容,隻适用于小規模地檢索,資料規模大了以後性能非常差。
TableStore解法
表格存儲(TableStore)引入多元索引(SearchIndex)功能後,完全覆寫傳統SQL所支援的字首比對和通配符比對,并且提供針對不同場景的精細化模糊查詢功能,性能優異。本節将以電商訂單為背景逐一講解。
定義手機号字段consumerCell為KEYWORD類型,建立多元索引,用PrefixQuery即可對原始字段進行字首比對查詢。例如,查詢consumerCell字段以'135'開頭的行,等價于SQL中子句consumerCell like '135%'。
核心代碼
//建立索引
indexSchema.addFieldSchema(new FieldSchema(CONSUMER_CELL, FieldType.KEYWORD));
//查詢
PrefixQuery prefixQuery = new PrefixQuery();
prefixQuery.setFieldName(CONSUMER_CELL);
prefixQuery.setPrefix("13580");
通配符查詢
如同字首查詢(PrefixQuery),通配符查詢(WildcardQuery)可以對原始字元串進行更靈活一些的比對。例如,查詢consumerCell字段中以'135'開頭并且中間包含'8066'的行,類比SQL中子句consumerCell like '135%8066%'。在表格存儲中可以把consumerCell定義為KEYWORD類型,建立多元索引,然後用WildcardQuery進行通配符比對。要比對的值可以是一個帶有通配符的字元串,用星号("*")代表0個或多個任意字元,用問号("?")代表任意單個字元。
需要注意的是,不能以“*”開頭,且模式字元長度不能超過10位元組。
如何實作字尾比對
通配符查詢不能以“*”開頭,若要實作字尾比對,可将字元串翻轉,再用PrefixQuery/WildcardQuery查詢。
在訂單場景中,“收貨人姓名”、“産品名”和“收貨位址”這類字段可能包含漢字、英文、數字等,查詢時需要以“單個漢字”或“英文單詞”為粒度切分字元串并建立索引。查詢同理,以“單個漢字”或“英文單詞”為粒度對查詢關鍵詞字元串進行分詞,在索引中進行查找比對。
例如,訂單表中,某行的産品名稱字段值為"Xiaomi/小米redmi note 7 pro 紅米索尼4800萬智能手機",期望用"xiaomi", "小米", "note", "pro"都能比對到該條記錄。可以使用預設分詞器SingleWord分詞器。
TEXT類型索引列預設使用SingleWord分詞器,按“單個漢字”切分中文,按“單個單詞”切分英文,大小寫字母不敏感,且單詞不會被拆分為子詞。例如,字段值"Xiaomi/小米redmi note 7 pro 紅米索尼4800萬智能手機"會被切分為詞條:"xiaomi", "小", "米", "redmi", "note", "7", "pro", "紅", "米", "索", "尼", "4800", "萬", "智", "能", "手", "機",并建立反向索引。
SingleWord支援配置參數CaseSensitive設定是否大小寫敏感;參數DelimitWord表示是否将單詞拆成子詞。例如,當設定SingleWord的參數DelimitWord=true, CaseSensitive=true,TEXT字段值"TableStore"會被切分為"Table"和"Store"。
查詢時若不在乎查詢關鍵詞分詞後的順序,用MatchQuery即可滿足需求。對于特定場景,對查詢關鍵詞被被分詞後順序敏感,可以考慮使用MatchPhraseQuery。
//建立索引
//等價于:indexSchema.addFieldSchema(new FieldSchema(PRODUCT_NAME, FieldType.TEXT));
indexSchema.addFieldSchema(new FieldSchema(PRODUCT_NAME, FieldType.TEXT).setAnalyzer(FieldSchema.Analyzer.SingleWord));
//查詢
MatchQuery matchQuery = new MatchQuery();
matchQuery.setFieldName(PRODUCT_NAME);
matchQuery.setText("Xiaomi/小米redmi note 7 pro 紅米索尼4800萬智能手機");
某些場景下,當使用者在搜尋框中鍵入部分關鍵字,就召回盡可能多的結果。這樣,可以避免使用者輸入錯誤的關鍵字,将其引導到“意中有語中無”的正确結果,提升使用者體驗。例如,訂單表中包含某手機型号為"HUAWEI P30PRO",一種良好的查詢體驗是:僅當鍵入"P30","30"或者"PRO"時,就可以查出這行記錄并回報使用者。此時,您可以考慮使用Fuzzy分詞器。
Fuzzy分詞器可以對字元串進行最細粒度的拆分,可以提升查詢召回率,但也造成多元索引存儲量膨脹,是以需要謹慎使用。其原理是設定一個“最小字元串長度視窗(minChars)”和“最大字元串長度視窗(maxChars)”,周遊[minChars, maxChars]視窗大小對TEXT類型字段值進行切分,并對所有切分後的字元串建立倒排。minChars預設為1,maxChars預設為3。
對“産品型号”建立TEXT索引,并使用Fuzzy分詞器以後,字段值"HUAWEI P30PRO"會被切分為詞條:"h", "hu", "hua", "u", "ua", "uaw", "a", "aw", "awe", "w", "we", "wei", "e", "ei", "i", "p", "p3", "p30", "3", "30", "30p", "0", "0p", "0pr", "pr", "pro", "r", "ro", "o",并建立反向索引。是以,用"p30", "P30", "30", "PRO", "pro"查詢時都可以比對到。同時也可以看出,Fuzzy分詞後索引資料量急劇膨脹,是以限制maxChars和minChars的內插補點不超過6,如果您需要自定義minChars和maxChars時需謹慎。
//建立索引
indexSchema.addFieldSchema(new FieldSchema(PRODUCT_TYPE, FieldType.TEXT)
.setAnalyzer(FieldSchema.Analyzer.Fuzzy)
.setAnalyzerParameter(new FuzzyAnalyzerParameter(1, 4)));
//查詢
MatchQuery matchQuery = new MatchQuery();
matchQuery.setFieldName(PRODUCT_TYPE);
matchQuery.setText("P30");
代碼示例
訂單表結構
以訂單系統的訂單表(表名order)為例,可能包含以下字段:
列名 | 資料類型 | 索引類型 | 字段說明 |
---|---|---|---|
order_id_md5 | string | - | 主鍵列:md5(order_id)避免熱點 |
order_id | KEYWORD | 主鍵列:訂單id | |
order_status | long | LONG | 訂單狀态 |
order_time | 下單時間 | ||
pay_time | 支付時間 | ||
deliver_time | 發貨時間 | ||
receive_time | 收貨時間 | ||
product_id | 商品id | ||
product_name | TEXT | 産品名 | |
product_type | 産品型号 | ||
consumer_id | 收貨人id | ||
consumer_name | 收貨人姓名 | ||
consumer_cell | 收貨人聯系方式 | ||
consumer_address | 收貨位址 |
項目代碼
完整代碼在這裡找到:
https://github.com/aliyun/tablestore-examples/tree/master/feature/FuzzySearch附錄
除了上文提到的SingleWord和Fuzzy分詞器以外,多元索引還支援以下分詞器——
MaxWord分詞器
MaxWord分詞器将英文切分成單詞,将中文切分成盡可能多的詞語/詞組。對中文分詞時,會做多層語義分詞,一般為兩層,第一層按最短語義切分,第二層按最長語義切分,并将兩次切分後的數組合并。例如字元串"菊花茶",第一層切分為["菊花"、"花茶"],第二層切分為["菊花茶"],合并後為["菊花"、"花茶"、"菊花茶"]。
MinWord分詞器
MinWord分詞器将英文切分成單詞,将中文切分為盡可能少的詞語/詞組。對中文分詞時,隻會按最長語義切分,例如字元串"菊花茶",會被切分為["菊花茶"]。
Split分詞器
Split分詞器允許您按照自定義分隔符對字元串進行分詞。例如,用字元串内容用逗号(","),将Split分詞器的分隔符設定為",",可以按照","切分并建構索引。
總結
表格存儲多元索引(SearchIndex)為海量訂單資料提供了豐富的查詢類型,而模糊查詢使得使用者在不給出完整準确的查詢關鍵字就能實作近似比對,大大提升了訂單資料的查詢易用性,發揮出存儲的更多潛在價值。
本文以海量電商訂單管理為背景,通過幾個具體案例,帶您了解了多元索引強大的模糊查詢功能。如有更多疑問,歡迎加入我們的技術支援群: