2020年10月23日 星期五

2020年10月19日 星期一

在 Vespa 使用 Parent/Child 時的限制

Parent/Child 的關聯在實務運用上挺方便的,可以讓有重複的內容統一放在 Parent document 上,使得 Child document 只要單純繼承 Parent 就可以一併繼承那些重複的內容。不過其實它相應的限制其實也頗多,而且這個部份在 Vespa 的文件上寫得並沒有非常清楚。

難以繼承複雜的結構

近期連續遇到的狀況就是,在 Search Definition 上定義欄位時不一定會出現錯誤,但結果實際上繼承是無法生效的。舉例來說,Parent document 上如果是 Array<StructA>,其中 StructA 裡面又包含了 StructB 的狀況時,結果是部署時並不會被檢查出錯誤,但實際上 StructB 無法正常地被 Child document 繼承到。

{
    "weapons": [{
        "type": "sword",
        "material": "iron",
        "price": 300,
        "position": {
            "longitude": 0.0,
            "latitude": 0.0
        }
    }, {
        "type": "sword",
        "material": "mythril",
        "price": 9000,
        "position": {
            "longitude": 0.0,
            "latitude": 0.0
        }
    }]
}

以這個例子來說,Search Definition 可能會長這樣:

struct Weapon {
    field type type string {}
    field material type string {}
    field price type double {}
    field position type map<string, string> {}
}

field weapons type array<Weapon> {
    indexing: summary
    struct-field type { indexing: attribute }
    struct-field material { indexing: attribute }
    struct-field price { indexing: attribute }
    struct-field position.key { indexing: attribute }
    struct-field position.value { indexing: attribute }
}

在這種狀況下,deployment 的檢查都會通過,但實際上 position 這個欄位是無法正常被繼承的。真的進行 Child document 的搜尋時,會發現 position 這個欄位一直都不會出現,但除了 position 以外的其他幾個欄位則都會正常出現。同時如果對 Parent document 呼叫 Document API,還是會看到包含 position 在內的所有欄位都正常地有值。

除了這個例子以外,另外嘗試在 Parent document 有非巢狀但格式有點複雜的欄位型態 map<string, array<string>> 時,結果則是在驗證階段直接拋出錯誤訊息:

For search 'childDocument', import field 'importedField': Field 'mapWithStringArray' via reference field 'weaponReference': Is not an attribute field. Only attribute fields supported

這個部份 Vespa 已經更新了文件 [3],稍微更詳細一點地說明了可支援的型態。可以參考 Vespa 的文件 [1-2]。

踩了幾次地雷以後,簡要來說,就是不要想在 Parent document 上擺什麼複雜的結構,除非那個欄位沒有要被 Child document 繼承,否則還是都用基本型別,最複雜大概就只到 array<struct> 或者 map<string, string> 這種就好了…..。

無法使用 index

因為 Parent document 是 global document,意味著它會被放在所有 content node 的記憶體中,因此它沒有辦法使用需要用到 disk 的 index。更確切地說,是 Child document 在繼承 Parent document 的欄位時,它只能繼承到被定義為 attribute 的欄位而已,index 的欄位無法被繼承。而這個限制也同時導致了繼承下來的欄位沒辦法做 partial match,只能夠作為 filter 來使用而已。

參考資料
  1. Parent/Child
  2. import-field
  3. Clarify restrictions that apply for imported field types.