Informacje o sposobie działania filtrów kolekcji OData w usłudze Azure AI Search
Ten artykuł zawiera podstawowe informacje dla deweloperów, którzy piszą zaawansowane filtry ze złożonymi wyrażeniami lambda. W tym artykule wyjaśniono, dlaczego istnieją reguły dotyczące filtrów kolekcji, eksplorując sposób wykonywania tych filtrów przez usługę Azure AI Search.
Podczas tworzenia filtru dla pól kolekcji w usłudze Azure AI Search można używać any
operatorów i all
wraz z wyrażeniami lambda. Wyrażenia lambda to wyrażenia logiczne odwołujące się do zmiennej zakresu. W filtrach używających wyrażenia any
lambda operatory i all
są analogiczne do for
pętli w większości języków programowania, a zmienna zakresu przyjmuje rolę zmiennej pętli i wyrażenie lambda jako treść pętli. Zmienna zakresu przyjmuje wartość "current" kolekcji podczas iteracji pętli.
Przynajmniej tak działa koncepcyjnie. W rzeczywistości usługa Azure AI Search implementuje filtry w zupełnie inny sposób działania for
pętli. W idealnym przypadku ta różnica byłaby dla Ciebie niewidoczna, ale w pewnych sytuacjach tak nie jest. Wynikiem końcowym jest to, że istnieją reguły, które należy przestrzegać podczas pisania wyrażeń lambda.
Uwaga
Aby uzyskać informacje na temat reguł filtrów kolekcji, w tym przykładów, zobacz Rozwiązywanie problemów z filtrami kolekcji OData w usłudze Azure AI Search.
Dlaczego filtry kolekcji są ograniczone
Istnieją trzy podstawowe przyczyny, dla których funkcje filtrowania nie są w pełni obsługiwane dla wszystkich typów kolekcji:
- Tylko niektóre operatory są obsługiwane w przypadku niektórych typów danych. Na przykład nie ma sensu porównywać wartości
true
logicznych ifalse
używaćlt
wartości ,gt
itd. - Usługa Azure AI Search nie obsługuje skorelowanego wyszukiwania w polach typu
Collection(Edm.ComplexType)
. - Usługa Azure AI Search używa odwróconych indeksów do wykonywania filtrów dla wszystkich typów danych, w tym kolekcji.
Pierwszą przyczyną jest tylko sposób definiowania języka OData i systemu typów EDM. Ostatnie dwa zostały wyjaśnione bardziej szczegółowo w pozostałej części tego artykułu.
Skorelowane i niekorelowane wyszukiwanie
W przypadku zastosowania wielu kryteriów filtrowania w kolekcji obiektów złożonych kryteria są skorelowane, ponieważ mają zastosowanie do każdego obiektu w kolekcji. Na przykład następujący filtr zwraca hotele, które mają co najmniej jeden pokój typu deluxe z stawką mniejszą niż 100:
Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)
Jeśli filtrowanie było niekorzystywane, powyższy filtr może zwrócić hotele, w których jeden pokój jest deluxe, a inny pokój ma stawkę podstawową mniejszą niż 100. Nie miałoby to sensu, ponieważ obie klauzule wyrażenia lambda mają zastosowanie do tej samej zmiennej zakresu, czyli room
. Dlatego takie filtry są skorelowane.
Jednak w przypadku wyszukiwania pełnotekstowego nie ma możliwości odwoływania się do określonej zmiennej zakresu. Jeśli używasz wyszukiwania w polu, aby wydać pełne zapytanie Lucene w następujący sposób:
Rooms/Type:deluxe AND Rooms/Description:"city view"
Możesz dostać hotele z powrotem, gdzie jeden pokój jest deluxe, a inny pokój wspomina "widok na miasto" w opisie. Na przykład poniższy dokument z elementem 1
będzie zgodny z Id
zapytaniem:
{
"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" }
]
}
]
}
Przyczyną jest to, że Rooms/Type
odnosi się do wszystkich analizowanych terminów Rooms/Type
pola w całym dokumencie i podobnie dla Rooms/Description
elementu , jak pokazano w poniższych tabelach.
Sposób Rooms/Type
przechowywania wyszukiwania pełnotekstowego:
Termin w Rooms/Type |
Identyfikatory dokumentów |
---|---|
Deluxe | 1, 2 |
standardowa | 1 |
Sposób Rooms/Description
przechowywania wyszukiwania pełnotekstowego:
Termin w Rooms/Description |
Identyfikatory dokumentów |
---|---|
dziedziniec | 2 |
miejscowość | 1 |
ogród | 1 |
duży | 1 |
motel | 2 |
pokój | 1, 2 |
standardowa | 1 |
suita | 1 |
wyświetl | 1 |
Tak więc w przeciwieństwie do powyższego filtru, który w zasadzie mówi "dopasowanie dokumentów, w których pokój ma Type
wartość "Deluxe Room", a ten sam pokój ma BaseRate
mniej niż 100", zapytanie wyszukiwania mówi "match documents where Rooms/Type
has the term "deluxe" and Rooms/Description
has the phrase "city view". Nie ma pojęcia poszczególnych pomieszczeń, których pola mogą być skorelowane w tym drugim przypadku.
Odwrócone indeksy i kolekcje
Być może zauważysz, że istnieje znacznie mniej ograniczeń dotyczących wyrażeń lambda w przypadku złożonych kolekcji, niż w przypadku prostych kolekcji, takich jak Collection(Edm.Int32)
, Collection(Edm.GeographyPoint)
i tak dalej. Dzieje się tak, ponieważ usługa Azure AI Search przechowuje złożone kolekcje jako rzeczywiste kolekcje dokumentów podrzędnych, podczas gdy proste kolekcje nie są w ogóle przechowywane jako kolekcje.
Rozważmy na przykład pole kolekcji ciągów z możliwością filtrowania, takie jak seasons
w indeksie dla sprzedawcy internetowego. Niektóre dokumenty przekazane do tego indeksu mogą wyglądać następująco:
{
"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"]
}
]
}
Wartości seasons
pola są przechowywane w strukturze nazywanej indeksem odwróconym, który wygląda następująco:
Term | Identyfikatory dokumentów |
---|---|
wiosna | 1, 2 |
lato | 1 |
jesień | 1, 2 |
zima | 2, 3 |
Ta struktura danych została zaprojektowana tak, aby odpowiedzieć na jedno pytanie z dużą szybkością: w jakich dokumentach pojawia się dany termin? Odpowiadanie na to pytanie działa bardziej jak zwykłe sprawdzanie równości niż pętla w kolekcji. W rzeczywistości dlatego w przypadku kolekcji ciągów usługa Azure AI Search zezwala eq
tylko jako operator porównania wewnątrz wyrażenia lambda dla elementu any
.
Następnie przyjrzymy się, jak można połączyć wiele kontroli równości dla tej samej zmiennej zakresu za pomocą polecenia or
. Działa dzięki algebra i właściwości dystrybucyjnej kwantyfikatorów. To wyrażenie:
seasons/any(s: s eq 'winter' or s eq 'fall')
jest odpowiednikiem:
seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')
a każde z dwóch any
wyrażeń podrzędnych można wydajnie wykonać przy użyciu odwróconego indeksu. Ponadto dzięki negacji prawa kwantyfikatorów to wyrażenie:
seasons/all(s: s ne 'winter' and s ne 'fall')
jest odpowiednikiem:
not seasons/any(s: s eq 'winter' or s eq 'fall')
dlatego można używać z all
usługami ne
i and
.
Uwaga
Chociaż szczegóły wykraczają poza zakres tego dokumentu, te same zasady rozszerzają się na odległość i testy przecięcia dla kolekcji punktów geoprzestrzeniowych. Dlatego w pliku :any
geo.intersects
nie można negowaćgeo.distance
należy porównać przy użyciu polecenialt
luble
- wyrażenia muszą być łączone z wyrażeniem
or
, a nieand
Reguły odwrotne dotyczą elementu all
.
W przypadku filtrowania kolekcji typów danych obsługujących lt
operatory , , gt
, le
i ge
, na Collection(Edm.Int32)
przykład, dozwolone są szersze wyrażenia. W szczególności można użyć and
funkcji , jak również or
w any
systemie , o ile bazowe wyrażenia porównania są łączone w porównania zakresów przy użyciu polecenia , które następnie są dalej łączone przy użyciu and
polecenia or
. Ta struktura wyrażeń logicznych nosi nazwę Disjunctive Normal Form (DNF), inaczej znaną jako "ORs of ANDs". Z drugiej strony wyrażenia lambda dla all
tych typów danych muszą znajdować się w postaci standardowej (CNF), inaczej znanej jako "ANDs of ORs". Usługa Azure AI Search umożliwia takie porównania zakresów, ponieważ może je wykonywać przy użyciu indeksów odwróconych wydajnie, podobnie jak w przypadku szybkiego wyszukiwania terminów dla ciągów.
Podsumowując, poniżej przedstawiono reguły kciuka dotyczące tego, co jest dozwolone w wyrażeniu lambda:
- W systemie
any
testy dodatnie są zawsze dozwolone, takie jak równość, porównania zakresów,geo.intersects
lubgeo.distance
w porównaniu zlt
luble
(pomyśl o "zbliżeniu" jako o równości, jeśli chodzi o sprawdzanie odległości). - Wewnątrz
any
elementuor
jest zawsze dozwolone. Można użyćand
tylko dla typów danych, które mogą wyrażać kontrole zakresów, i tylko wtedy, gdy używasz jednostek ORS identyfikatorów AND (DNF). - Wewnątrz
all
reguły są odwrócone. Dozwolone są tylko testy ujemne , można używaćand
zawsze i można użyćor
tylko do sprawdzania zakresu wyrażonego jako AND jednostek ORS (CNF).
W praktyce są to typy filtrów, których najprawdopodobniej używasz mimo to. Nadal warto zrozumieć granice tego, co jest możliwe.
Aby zapoznać się z konkretnymi przykładami dozwolonych filtrów i których nie ma, zobacz Jak napisać prawidłowe filtry kolekcji.