分詞、匹配、相關性、排序表達式
針對目前若干用戶遇到的搜索結果與預期不符合的問題進行統一詳細說明,并以此為話題展開說明下OpenSearch在搜索效果方面的功能和后續一些工作方向。
首先,對于搜索來講,最常見的有兩種做法:
數據庫的like查詢,可以理解為簡單的包含關系;
百度、google等搜索引擎,涉及到分詞,將查詢詞根據語義切分成若干詞組term(這個是搜索引擎重難點之一),通過term組合匹配給相應文檔進行打分,根據分值排序,并最終返回給用戶。
OpenSearch采用的方式與上述搜索引擎做法基本一致。那這里就有三部分內容會影響搜索效果:1,分詞方式;2,匹配方式;3,相關性算分。
我們來分別說下這三部分在OpenSearch上的行為和表現。
接下來,我們詳細說明下各個字段的展現效果及適用場景,供大家參考。
分詞方式
熟悉各類分詞是本篇操作的前提,請務必先查閱 內置分析器文檔。
匹配方式
原理
分完詞后得到若干term,如何召回文檔,就涉及到匹配方式。目前OpenSearch內部默認支持的是AND,即一篇文檔中包含全部的term才能被搜索出來。當然這是對同一關鍵詞而言的,除此之外系統還支持多種匹配方式,如AND、OR、RANK、NOTAND以及(),優先級從高到低為(),ANDNOT,AND,OR,RANK。
舉例
關系 | 用法 | 含義 |
query=title:”蘋果 手機” | 查詢title中包含蘋果和手機的文檔 | |
AND | query=title:’蘋果’ AND cate:’手機’ | 交集。查詢title中包含蘋果,且cate包含手機的文檔 |
OR | query=title:’蘋果’ OR cate:’手機’ | 并集。查詢title中包含蘋果,或cate包含手機的文檔 |
RANK | query=title:’蘋果’ RANK cate:’手機’ | 查詢title中包含蘋果的文檔,如果cate包含手機則可以加分 |
ANDNOT | query=title:’蘋果’ ANDNOT cate:’手機’ | 查詢title中包含蘋果,但cate不包含手機的文檔 |
案例
問:我文檔中包含“吃飯了”,我搜索“吃飯”、“吃飯了”都能召回,搜索“吃飯了嗎”沒結果?
答:因為目前OpenSearch是要求全部的分詞結果都匹配才能召回文檔,上面的“嗎”在文檔中沒有出現,所以無法召回。但可以通過查詢分析解決。
問:我只想查找某些詞排在最前面的文檔,比如以“肯德基”開頭的文檔;答:目前不支持位置相關召回。
相關性算分
上面提到的都是跟召回相關的技術,召回文檔之后,究竟文檔如何排序就涉及到相關性。目前OpenSearch有sort子句來支持用戶自定義排序。如果不設置sort,則默認為sort=-RANK;sort本身支持多維排序,以及升降序的支持。比如sort=-RANK;+bonus,意思為第一位按照相關性降序排序,相關性分值一樣的文檔再按照bonus升序排列。這里我們重點描述下RANK的用法,RANK即為OpenSearch中的相關性設置,主要分為兩部分:基礎排序(粗排)和業務排序(精排)。
原理
OpenSearch相關性算分策略為,取召回的rank_size(目前是100萬)個文檔按照粗排表達式的定義進行算分;取粗排分最高的N個結果(百級別)按照精排表達式進行算分,并排序;然后根據start與hit的設置取相應結果返回給用戶。如果用戶獲取的結果超過了精排結果數N,則后續按照粗排分數排序結果繼續展現。
基礎排序-(粗排)表達式:從上面原理介紹中可以看出粗排對性能(latency)的影響非常大,但同時粗排又非常的重要,否則會出現好的文檔無法進入精排而導致文檔不能被最終展現。所以粗排要盡量的簡單有效,目前OpenSearch的粗排只支持幾個簡單的正排字段、靜態bm25、時效分等因素。
業務排序-(精排)表達式:通過粗排表達式篩選出較優質的N個文檔進行詳細排序,精排表達式中支持復雜的數學計算、邏輯等,并且OpenSearch提供了豐富的典型場景(如O2O類)的function和feature來滿足日常的相關性需求。
同時,系統以內置了多個場景的應用結構和排序表達式,可以供大家參考和使用。
舉例
場景 | 表達式 | 含義 |
論壇-粗排 | static_bm25() | 簡略文本分 |
論壇-精排 | text_relevance(title)*3+text_relevance(body) + if(text_relevance(title)>0.07,timeliness(create_timestamp),timeliness(create_timestamp)*0.5) + (topped+special+atan(hits)*0.5+atan(replies))*0.1 | 文本分 、 時效分 、 其他屬性分 |
O2O-粗排 | sold_score+general_score*2 | 銷量、門店綜合分值(離線算好) |
O2O-精排 | 2*sold_score+0.5*reward - 10*distance(lon,lat,u_posx,u_posy) + if ((flags&2) =2, 2, 0)+if(is_open=5,10,0) + special_score | 銷量、配送速度及準點率 、 距離 、 是否繁忙、是否在營業時間 、 人工干預 |
小說-粗排 | static_bm25()*0.7+hh_hot*0.00003 | 文本分、熱度 |
小說-精排 | pow(min(0.5,max(text_relevance(category),max(text_relevance(title), text_relevance(author)))),2) + general_score*2 + 1.5*(1/(1+pow(2.718281,-((log10(hh_hot)-2)*2-5))))) | 分類相關性、標題相關性、作者相關性 、 小說質量 、 小說熱度 |
電商-粗排 | static_bm25()+general_score*2+timeliness(end_time) | 文本分、寶貝綜合分值、過期時間 |
電商-精排 | text_relevance(title)*3+text_relevance(category) + general_score*2+boughtScore*2 + tag_match(ctr_query_value,doc_value,mul,sum,false,true)+.. | 文本相關性、類目相關性 、 寶貝人氣、賣家分 、 ctr預估、特征規則分等 |
案例
問:精排表達式text_relevance(seller_id)報找不到字段答:text_relevance()只支持TEXT及SHORT_TEXT類型,其他不可以。
問:查詢報2112錯誤,是什么問題?答:查詢語句(query子句)必須與formula相配合,比如query=default:’keyword’,default中包含title和body字段,而formula指定text_relevance(title)+text_relevance(author)則會報錯,因為author在default中不存在。
使用技巧
排序表達式的算分是在查詢結算對每個文檔進行計算的,所以如果跟查詢無關的部分的計算可以預先離線計算好,新增一個general_score字段來存放,排序的時候只要使用general_score字段即可,避免大量計算過程,提高查詢性能。
tag_match的feature允許用戶將query中的特征與doc中特征做多維運算,在電商場景下有著非常廣泛的用途,有類似的需求的用戶可以研究下。
OpenSearch提供了豐富的function和feature,使用得當可以獲得非常強大的功能。
相關性有很多部分共同組成,各項之間的權重需要根據搜索排序效果不斷進行調整以達到一個用戶滿意的搜索效果。