了解 OData 集合篩選條件如何在 Azure AI 搜尋服務中運作
本文為使用複雜 Lambda 表達式撰寫進階篩選條件的開發人員提供了背景知識。 本文會透過探索 Azure AI 搜尋服務如何執行這些篩選條件,進一步說明集合篩選條件的規則存在原因。
在 Azure AI 搜尋服務上針對集合欄位建立篩選條件時,您可使用 any
和 all
運算子搭配 Lambda 運算式。 Lambda 運算式是參考範圍變數的布林運算式。 在使用 Lambda 表達式的篩選條件中,any
和 all
運算子類似於大部分程式設計語言中的 for
迴圈,其範圍變數會採用迴圈變數的角色並將 Lambda 運算式視為迴圈主體。 在反覆運算回區期間,範圍變數為集合的「目前」值。
這是大致上如何運作的概念。 實際上,Azure AI 搜尋服務實作篩選條件的方式與 for
迴圈運作方式大不相同。 在理想情況下,您不會察覺差異,但在某些情況下,則顯而易見。 最終結果是撰寫 Lambda 運算式時必須遵循規則。
注意
如需集合篩選條件規則用途的相關資訊和範例,請參閱針對 Azure AI 搜尋服務中的 OData 集合篩選條件進行疑難排解。
為何限制集合篩選條件
並非所有集合類型都支援篩選功能,三個基本原因如下:
- 特定資料類型僅支援某些運算子。 例如,使用
lt
、gt
等來比較布林值true
和false
並不恰當。 - Azure AI 搜尋服務不支援類型
Collection(Edm.ComplexType)
欄位的相關聯搜尋。 - Azure AI 搜尋服務會使用反向索引來對包含集和在內的所有類型資料執行篩選條件。
第一個原因僅是定義 OData 語言和 EDM 類型系統的結果。 本節的其餘部分將詳細說明後續兩個原因。
相關聯與不相關聯搜尋
當您對複雜物件集套用多個篩選準則時,準則將相關聯,因為會套用至集合中的每個物件。 例如,下列篩選條件將傳回至少有一間豪華客房且價格低於 100 的旅館:
Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)
如果篩選不相關聯,則上述篩選條件可能會傳回飯店,其中有一間豪華客房和一間基本費率低於 100 的不同房型客房。 這並不合理,因為 Lambda 運算式的兩個子句都套用製相同範圍變數,亦即 room
。 這便是為何這類篩選條件相關聯的原因。
然而,針對全文檢索搜尋,則無法參考特定範圍變數。 如果您使用欄位搜尋來發出完整的 Lucene 查詢,如下所示:
Rooms/Type:deluxe AND Rooms/Description:"city view"
您可能會在說明中取得其中一間為豪華客房,另一間客房則提及「市景」的旅館。 例如,下方 Id
為 1
的文件會符合查詢:
{
"value": [
{
"Id": "1",
"Rooms": [
{ "Type": "deluxe", "Description": "Large garden view suite" },
{ "Type": "standard", "Description": "Standard city view room" }
]
},
{
"Id": "2",
"Rooms": [
{ "Type": "deluxe", "Description": "Courtyard motel room" }
]
}
]
}
原因是 Rooms/Type
會參考整個文件中 Rooms/Type
欄位的所有分析字詞,Rooms/Description
亦是如此,如下表所示。
全文檢索搜尋如何儲存 Rooms/Type
:
Rooms/Type 中的字詞 |
文件識別碼 |
---|---|
豪華 | 1, 2 |
standard | 1 |
全文檢索搜尋如何儲存 Rooms/Description
:
Rooms/Description 中的字詞 |
文件識別碼 |
---|---|
庭院 | 2 |
市/鎮 | 1 |
花園 | 1 |
大型 | 1 |
汽車旅館 | 2 |
房間 | 1, 2 |
standard | 1 |
套房 | 1 |
檢視 | 1 |
因此,與上述篩選條件不同,其基本上表示「比對文件,其中客房有等於「豪華客房」的 Type
,且該相同客房的 BaseRate
低於 100」,而搜尋查詢則表示「比對文件,其中 Rooms/Type
有字詞「豪華」,且「市景」為 Rooms/Description
的片語」。 在後者案例中,沒有個別客房且其欄位可相關聯的概念。
反向索引和集合
您可能已注意到,相較於 Collection(Edm.Int32)
、Collection(Edm.GeographyPoint)
等簡單集合,複雜集合的 Lambda 運算式限制會相對較少。 這是因為 Azure AI 搜尋服務將複雜集合儲存為子文件的實際集合,而簡單集合完全不會儲存為集合。
例如,請針對線上零售商考慮可篩選的字串集合欄位 (如索引中的 seasons
)。 上傳至此索引的某些文件可能會如下所示:
{
"value": [
{
"id": "1",
"name": "Hiking boots",
"seasons": ["spring", "summer", "fall"]
},
{
"id": "2",
"name": "Rain jacket",
"seasons": ["spring", "fall", "winter"]
},
{
"id": "3",
"name": "Parka",
"seasons": ["winter"]
}
]
}
seasons
欄位的值會儲存在名為反向索引的結構中,如下所示:
詞彙 | 文件識別碼 |
---|---|
spring | 1, 2 |
夏天 | 1 |
秋天 | 1, 2 |
冬天 | 2、3 |
此資料結構專設計用來即時回答一個問題:哪些文件會顯示指定的字詞? 回答此問題更像是一般相等檢查,而不是對集合執行迴圈。 事實上,這就是為什麼針對字串集合,Azure AI 搜尋只允許 eq
在 Lambda 運算式中作為 any
的比較運算符。
接下來,我們將探討如何使用 or
在相同範圍變數上組合多個相等檢查。 由於代數和量詞的分配律,而可順利運作。 此運算式:
seasons/any(s: s eq 'winter' or s eq 'fall')
等於:
seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')
您可使用反向索引,有效執行這兩個 any
子運算式。 此外,由於量詞的否定率,此運算式:
seasons/all(s: s ne 'winter' and s ne 'fall')
等於:
not seasons/any(s: s eq 'winter' or s eq 'fall')
如此便可搭配 all
使用 ne
和 and
。
注意
即使詳細資料超出本文件的範圍,但這些相同原則也會延伸至地理空間點集合的距離和交集測試。 這就是為何,在 any
中:
geo.intersects
無法否定geo.distance
必須使用lt
或le
進行比較- 運算式必須與
or
合併,而非and
相反規則適用於 all
。
當對支援 lt
、gt
、le
和 ge
(例如 Collection(Edm.Int32)
) 資料類型的集合進行篩選時,允許各種運算式。 具體而言,只要基本比較運算式使用 and
來合併成範圍比較 (進一步會使用 or
進行合併),您便可在 any
中使用 and
和 or
。 此布林運算式的結構稱為析取正規式 (DNF),也稱為 "ORs of ANDs"。 相反地,針對 all
,這些資料類型的 Lambda 運算式必須是合取正規式 (CNF),也稱為 "ANDs of ORs"。 Azure AI 搜尋服務允許這類範圍比較,因為可使用反向索引來有效執行,如快速查閱字串的字詞一樣。
總而言之,以下是 Lambda 運算式中允許的經驗法則:
- 在
any
內,一律允許正定檢查,例如相等、範圍比較、geo.intersects
,或與lt
或le
比較的geo.distance
(關於檢查距離方面,將「鄰近性」視為相等)。 - 在
any
內,一率允許or
。 只在使用 ORs of ANDs (DNF) 時,您才可將and
用於可表示範圍檢查的資料類型。 - 在
all
內,規則為反向。 僅允許否定檢查,您可以一律使用and
,並且or
只能用於表示為 OR 的 AND (CNF) 的範圍檢查。
實際上,這些是您最可能使用的篩選條件類型。 不過,瞭解可能的界限,仍對您有所幫助。
如需允許和不允許篩選條件類型的特定範例,請參閱如何撰寫有效集合篩選條件。