Vespa 有個 weightedset 的型態,我個人其實覺得 Vespa 的文件在針對 weightedset 的描述有點難懂,所以這邊會用範例來整理一下 weightedset 的實際效果。
weightedset 的格式
weightedset 從名字可以看出它是個 Set,並且是有權重的,所以可以蠻容易想像它的格式會長得像這樣:
{ "key1": 1, "key2": 10 }
這個是型態為 weightedset<string> 的狀況,我覺得應該也是大多數使用情境的狀況吧。weightedset 的型態宣告是在宣告它的 key 要使用什麼型態,不過除了 string 以外還能使用什麼型態,好像沒有在文件上看到。而 weightedset 的權重的部份,依據文件描述是只能使用 32-bit 數字,也就是說是不能有浮點數的。
weightedset 的用途
目前就我所知,weightedset 主要就是用在 match 和 rank 兩種地方。match 指的是找出具有特定 key 的 document;rank 則指的是依據權重讓 Vespa 調整找到的 document 的順序。接下來會分別針對 match 和 rank 有一些範例來說明 weightedset 產生的效果為何。
match 的範例
假設我有兩個 document,document 裡面有個欄位叫做 weights,型態是 weightedset<string>。schema 定義如下:
field weights type weightedset<string> { indexing: summary | attribute }
實際的資料假設長這樣:
doc #1: "weights": { "attribute1": 10, "attribute2": 4 } doc #2: "weights": { "attribute1": 130 }
若我們以 match attribute2 來搜尋的話,結果會是只能搜尋到 doc #1:
select * from test where weightedset(weights, {"attribute2": 1});
這個結果應該是蠻容易想像的,不管 weight 是給多少,因為都只有 doc #2 才有 attribute2 這個 key,所以只會找到 doc #2 而已。從效能考量來說,Vespa 團隊也建議若可以的話,用 weightedset 取代 OR 的操作是比較好的選擇。舉例來說:
select * from test where weightedset(weights, {"attribute1": 1, "attribute2": 1});
上述的 YQL 可以同時搜尋到 doc #1 和 doc #2,也就是說它實際的搜尋效果跟下面用 OR 的 query 是差不多的。
select * from test where weights contains "attribute1" OR weights contains "attribute2";
rank 的範例
rank 其實是 weightedset 比較奇妙的地方。而且不知道是不是我漏看了或者我看不懂,我沒有看到 Vespa 文件裡對於 weightedset 有太詳細的描述…。
首先,我們還是跟上面一樣使用相同的測試資料:
doc #1: "weights": { "attribute1": 10, "attribute2": 4 } doc #2: "weights": { "attribute1": 130 }
假設我們執行的 query 是指定 attribute1 的權重為 1,那麼結果會是如何呢?
select * from test where weightedset(weights, {"attribute1": 1});
本來我自己以為結果應該會是 doc #2 在前面、doc #1 在後面,因為 doc #2 欄位裡的 attribute1 權重比較高,算出來的分數應該會比較多才對!但結果我錯了 。
{ "id": "id:test:test::doc1", "relevance": 0.0017429193899782135, .... }, { "id": "id:test:test::doc2", "relevance": 0.0017429193899782135, .... }
結果顯示,兩個 document 得到的分數是一樣的!
接著如果改成在 query 裡將 attribute 1 的權重從 1 提昇到 100 的話呢….
YQL: select * from test where weightedset(weights, {"attribute1": 100}); results: { "id": "id:test:test::doc1", "relevance": 0.17429193899782136 .... }, { "id": "id:test:test::doc2", "relevance": 0.17429193899782136, .... }
跟前一個結果比較起來,其實可以發現,兩個 document 的分數也同時增加了 100 倍!
如果把 query 改為找 attribute 2,權重一樣是 100 的話呢?
YQL: select * from test where weightedset(weights, {"attribute2": 100}); results: { "id": "id:test:test::doc1", "relevance": 0.17429193899782136, .... }
可以看到結果是只會搜尋到 doc #1,但是它得到的分數跟上一個測試一樣,都是 0.17429193899782136。
到這裡其實就可以歸納出 weightedset 的規則了。weightedset 在預設的 native rank 裡,是完全不參考 field 裡的權重,單純只有參考 query 的權重而已。所以在第一和第二個測試中,attribute1 的權重給 1 的時候,doc #1 和 doc #2 會得到相同的分數,因為它們都有 attribute1 這個 key,但由於只計算 query 的權重,也沒有其他因子,因此它們會獲得完全一樣的分數。而第三個測試則是因為 doc #2 沒有 attribute2,所以根本不會被搜尋到。同時,在沒有其他因子的情況下,query 的權重提高 N 倍,結果的分數也會跟著提高 N 倍。
沒有留言:
張貼留言