子句說明
分層查詢一種查詢文法的擴充,主要功能是增強查詢文法對於召回過程的控制能力,讓應用可以根據自己的使用情境來加速文檔召回過程,提高系統整體效能,擴充的功能主要有以下幾點:
允許使用者通過某些方式選擇召回的區間
對於不同區間可以選擇召回的先後順序
對於不同區間可以指定不同的query來影響召回集
子句文法
名詞介紹
name | description |
seek | 查詢過程中,查詢到一個doc的操作 |
docid | HA3內部對文檔的編號,查詢時會按docid從小到大查詢。 |
[查詢]區間/range | 查詢時一個docid的範圍,這裡的range是指會被查詢的docid的範圍。 |
[查詢]層/layer | 層是由一個或者多個range組成的,層主要作用是決定查詢區間的優先順序(把不同range放到不同層)。[查詢]層/layer[查詢]區間/rangedocidseekname |
查詢文法
{
"layer" : [
]
}選擇召回區間
對於召回區間的控制主要通過layer文法來實現:
一個layer子句可以由多個single_layer組成,一個single_layer主要有兩個元素:
quota:用於設定當前層建議召回的doc個數,這裡有幾個點需要注意:
quota與rank_size的關係:各層quota總和不會大於rank_size,例如rank_size=10,quota:5;quota:7,這樣最終第二層的quota會被截斷到5。
當前層quota有剩餘的情況下,會自動把quota累加到下一層。
由於層內的每個區間之間的doc不一定滿足前面的doc比後面doc要好,所以quota有兩種作用機制,一種是每尋找到一個doc,就檢查一次quota是否有剩餘,另一種是在當前層內無視quota限制(依舊被rank_size限制),尋找完當前層,最後看是否有剩餘,若有剩餘則累加到下一層
當使用者顯示指定layer子句的時候,每層quota預設值是0,quota的最大值為uint32_t的最大值。
range :用於確定當前層的doc範圍,如果不寫,範圍區間為所有doc,及[0,docCount)。range文法基本工作原理是通過使用者給定的attribute,逐級計算最終需要seek的doc範圍。需要注意的點:
文法中用到的必須是attribute,不能是需要計算的運算式
文法中用到的attribute必須與離線排序方式相符,否則會自動轉換為查詢全部區間。
文法中用到的attribute必須要是連續出現的,不可以中間插入擴充關鍵字(%sorted,%docid等)
除了attribute外我們還支援幾種擴充語句:%sorted(這一層查詢排過序的全量和增量),%unsorted(這一層查詢未排序的資料,即時資料等),%other(除去前面層以外的範圍),%docid(直接指定docid區間查詢),%segmentid(直接指定segmentid區間查詢),%percent(指定這個範圍百分比範圍的區間查詢)
如果使用者在分層子句中沒有指定%sorted,%unsorted關鍵字,引擎會自動為使用者添加,預設模式是每層都是sorted,最後如果結果數不夠會為使用者多查一層即時資料
選擇不同區間的不同query
對於不同查詢層,可以使用不同的查詢詞,或者選擇不同的倒排鏈。不同query通過分號隔開,當layer的數目大於query數目時,會自動用最後一條query填充剩餘層。
使用樣本:
本節將介紹分層查詢與一些引擎提供的其他功能結合使用的情境下,如何搭配使用分層查詢。
構建索引時文檔排序,查詢指定召回區間
在使用離線的排序功能時,文檔是全域有序的,例如,按照網站排序後,同一個網站的文檔在索引中是連續的一段,當在某個網站內部查詢時,可以利用這個資訊來加快seek的速度,假定網站對應的attribute是site_id,查詢的網站ID為1和7,查詢詞為iphone:
{
"layer" : [
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [1,7]
}
]
},
"quota" : 5000
}
]
}或者如果網站1和7中查詢結果不夠的情況下,使用者還想查詢網站5和10的結果作為補充,可以這樣:
{
"layer" : [
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [1,7]
}
]
},
"quota" : 5000
},
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [5,10]
}
]
},
"quota" : 0
}
]
}由於是希望第一層結果不夠的情況下才查詢第二層,所以第二層的quota設定為0(或者不寫)。當然,使用者還可以進行多樣性召回:
{
"layer" : [
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [1,7]
}
]
},
"quota" : 4000
},
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [5,10]
}
]
},
"quota" : 1000
}
]
}對於離線排序是多維的情況,也可以支援多維區間的定位,還是以站內查詢為例,離線排序是先按網站排序,網站相同的,按照網頁的靜態分排序,這種時候,查詢希望召回靜態分大於100的網頁,查詢文法如下:
{
"layer" : [
{
"range" : {
"fields" : [
{
"field" : "site_id",
"values" : [1,7]
},
{
"field" : "static_score",
"values" : "[100,]"
}
]
},
"quota" : 4000
}
]
}
註:區間範圍表示加雙引號多query查詢
在某些情況下,使用者的查詢即擔心召回數目是否足夠,又希望召回數不能太多,導致影響查詢效能,比較常見的一類情境是,有多個查詢詞,以A,B為例:
query方式 | 召回數 | 效能 |
A AND B | 最少 | 最好 |
A OR B | 最多 | 最差 |
A RANK B/B RANK A | 適中 | 中等 |
上述的幾種query方式,對於A和B的召回數和效能都不一樣,大部分查詢希望的是有較好的召回,而且召回數不需要太多,這種情況下,固定用某種查詢方式,很難保證結果數和效能都適中。使用多query的方式就可以通過一次查詢來解決這個問題:
{
"query": "A OR B;A RANK B;A AND B",
"layer" : [
{
"quota" : 1000
},
{
"quota" : 1000
},
{
"quota" : 1000
}
]
}這種查詢方式可以兼顧召迴文檔數目和效能,對於查詢詞的關聯程度也有比較大的提升(對於大召回可以命中一些A AND B的結果,對於小召回可以通過A OR B來儘可能多召回)。
需要考慮時效性的查詢
有時候使用者會希望查詢結果的時效性比較好,在這種情況下使用者會希望先查詢即時的無序索引,之後再查詢全量和增量的有序索引,使用者也可以在有序索引中指定先查詢後面的一部分資料,再查前面的一部分資料,可以用percent實現
例如使用者想要先查詢時效性最好的即時索引,結果不夠的話查詢有序索引中後50%的doc,最後查詢前50%的doc,查詢詞為iphone:
{
"layer" : [
{
"range" : {
"index_type" : "%unsorted"
},
"quota" : 5000
},
{
"range" : {
"index_type" : "%sorted",
"fields" : [
{
"field" : "service_id",
"values" : [1,3]
}
],
"percent" : "[50,100)"
},
"quota" : 0
},
{
"range" : {
"index_type" : "%sorted",
"fields" : [
{
"field" : "service_id",
"values" : [1,3]
}
],
"percent" : "[0,50)"
},
"quota" : 0
}
]
}
註:percent關鍵字中可以指定不同多個區間,區間是左閉右開的注意事項
layer子句是可選子句