Informazioni sul funzionamento dei filtri della raccolta OData in Azure AI Search
Questo articolo fornisce informazioni generali per gli sviluppatori che scrivono filtri avanzati con espressioni lambda complesse. L'articolo spiega perché esistono le regole per i filtri delle raccolte esaminando il modo in cui Azure AI Search esegue questi filtri.
Quando si compila un filtro relativo ai campi della raccolta in Azure AI Search, è possibile usare gli operatori any
e all
insieme alle espressioni lambda. Le espressioni lambda sono espressioni booleane che fanno riferimento a una variabile di intervallo. Nei filtri che usano un'espressione lambda, gli operatori any
e all
sono analoghi a un ciclo for
nella maggior parte dei linguaggi di programmazione, con la variabile di intervallo che assume il ruolo della variabile di ciclo e l'espressione lambda come corpo del ciclo. La variabile di intervallo assume il valore "corrente" della raccolta durante l'iterazione del ciclo.
Almeno questo è il funzionamento a livello concettuale. In realtà, Azure AI Search implementa i filtri in modo molto diverso dal funzionamento dei cicli for
. Idealmente, questa differenza dovrebbe essere invisibile per l'utente, ma in alcune situazioni non lo è. Il risultato finale è che ci sono regole che è necessario seguire quando si scrivono espressioni lambda.
Nota
Per informazioni sulle regole per i filtri delle raccolte, inclusi esempi, vedere Risoluzione dei problemi relativi ai filtri della raccolta OData in Azure AI Search.
Perché i filtri delle raccolte sono limitati
Esistono tre motivi principali per cui le funzionalità dei filtri non sono completamente supportate per tutti i tipi di raccolte:
- Solo alcuni operatori sono supportati per determinati tipi di dati. Ad esempio, non ha senso confrontare i valori booleani
true
efalse
usandolt
,gt
e così via. - Azure AI Search non supporta la ricerca correlata nei campi di tipo
Collection(Edm.ComplexType)
. - Azure AI Search usa indici invertiti per eseguire filtri relativi a tutti i tipi di dati, incluse le raccolte.
Il primo motivo è solo una conseguenza della definizione del linguaggio OData e del sistema di tipi EDM. Gli ultimi due sono spiegati in modo più dettagliato nel resto di questo articolo.
Ricerca correlata e non correlata
Quando si applicano più criteri di filtro in una raccolta di oggetti complessi, i criteri sono correlati perché si applicano a ogni oggetto della raccolta. Ad esempio, il filtro seguente restituisce gli hotel che hanno almeno una camera deluxe con una tariffa inferiore a 100:
Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)
Se il filtro non fosse correlato, il filtro precedente potrebbe restituire gli hotel in cui una camera è deluxe e un'altra camera ha una tariffa di base inferiore a 100. Questo non avrebbe senso, perché entrambe le clausole dell'espressione lambda si applicano alla stessa variabile di intervallo, ovvero room
. Questo è il motivo per cui tali filtri sono correlati.
Tuttavia, per la ricerca full-text, non è possibile fare riferimento a una variabile di intervallo specifica. Se si usa la ricerca con campi per eseguire una query Lucene completa come quella seguente:
Rooms/Type:deluxe AND Rooms/Description:"city view"
è possibile recuperare gli hotel in cui una camera è deluxe e un'altra camera ha una descrizione che contiene l'espressione "city view". Ad esempio, il documento seguente con Id
uguale a 1
soddisferebbe la query:
{
"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" }
]
}
]
}
Il motivo è che Rooms/Type
fa riferimento a tutti i termini analizzati del campo Rooms/Type
nell'intero documento e in modo analogo a Rooms/Description
, come illustrato nelle tabelle seguenti.
Modalità di archiviazione di Rooms/Type
per la ricerca full-text:
Termine in Rooms/Type |
ID documento |
---|---|
deluxe | 1, 2 |
standard | 1 |
Modalità di archiviazione di Rooms/Description
per la ricerca full-text:
Termine in Rooms/Description |
ID documento |
---|---|
courtyard | 2 |
city | 1 |
garden | 1 |
grande | 1 |
motel | 2 |
room | 1, 2 |
standard | 1 |
suite | 1 |
view | 1 |
Quindi, a differenza del filtro precedente, che in sostanza dice "trova i documenti in cui una camera ha Type
uguale a "Deluxe Room" e la stessa camera ha BaseRate
inferiore a 100", la query di ricerca dice "trova i documenti in cui Rooms/Type
include il termine "deluxe" e Rooms/Description
include l'espressione "city view". Non esiste un concetto di singole camere i cui campi possono essere correlati nel secondo caso.
Indici invertiti e raccolte
Come è possibile osservare, esistono molte meno restrizioni per le espressioni lambda relative a raccolte complesse rispetto a quelle relative a raccolte semplici, ad esempio Collection(Edm.Int32)
, Collection(Edm.GeographyPoint)
e così via. Questo è dovuto al fatto che Azure AI Search archivia le raccolte complesse come effettive raccolte di documenti secondari, mentre le raccolte semplici non vengono nemmeno archiviate come raccolte.
Si consideri ad esempio il campo di una raccolta di stringhe filtrabile come seasons
in un indice per un rivenditore online. Alcuni documenti caricati in questo indice potrebbero essere simili al seguente:
{
"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"]
}
]
}
I valori del campo seasons
vengono archiviati in una struttura denominata indice invertito, che è simile a quanto segue:
Termine | ID documento |
---|---|
spring | 1, 2 |
summer | 1 |
fall | 1, 2 |
winter | 2, 3 |
Questa struttura di dati è progettata per rispondere molto velocemente a una domanda: in quali documenti è presente un determinato termine? Il processo che consente di recuperare la risposta a questa domanda è più simile a un semplice controllo di uguaglianza che all'esecuzione di un ciclo in una raccolta. Questo è il motivo per cui per le raccolte di stringhe, Azure AI Search consente solo eq
come operatore di confronto in un'espressione lambda per any
.
Si esaminerà ora come è possibile combinare più controlli di uguaglianza nella stessa variabile di intervallo con or
. Funziona grazie all'algebra e alla proprietà distributiva dei quantificatori. Questa espressione:
seasons/any(s: s eq 'winter' or s eq 'fall')
Equivale a:
seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')
e ognuna delle due sottoespressioni any
può essere eseguita in modo efficiente usando l'indice invertito. Inoltre, grazie alla legge di negazione dei quantificatori, questa espressione:
seasons/all(s: s ne 'winter' and s ne 'fall')
Equivale a:
not seasons/any(s: s eq 'winter' or s eq 'fall')
e questo è il motivo per cui è possibile usare all
con ne
e and
.
Nota
Anche se i dettagli non rientrano nell'ambito di questo documento, questi stessi principi si estendono anche ai test di distanza e intersezione per raccolte di punti geospaziali. Ecco perché, in any
:
geo.intersects
non può essere negatageo.distance
deve essere confrontata usandolt
ole
- Le espressioni devono essere combinate con
or
, non conand
Regole opposte si applicano a all
.
È consentita un'ampia gamma di espressioni quando si filtrano raccolte di tipi di dati che supportano gli operatori lt
, gt
, le
e ge
, ad esempio Collection(Edm.Int32)
. In particolare, è possibile usare and
e or
in any
, purché le espressioni di confronto sottostanti vengano combinate in confronti di intervalli usando and
e vengano quindi combinate ulteriormente usando or
. Questa struttura di espressioni booleane è denominata forma normale disgiuntiva (DNF), nota anche come "OR di AND". Al contrario, le espressioni lambda per all
per questi tipi di dati devono essere in forma normale congiuntiva (CNF), nota anche come "AND di OR". Azure AI Search consente confronti di intervalli di questo tipo perché può eseguirli usando indici invertiti in modo efficiente, proprio come può eseguire una ricerca rapida di termini per le stringhe.
Per riassumere, di seguito sono elencate le regole generali di ciò che è consentito in un'espressione lambda:
- In
any
, i controlli positivi sono sempre consentiti, ad esempio controlli di uguaglianza, confronti di intervallo,geo.intersects
ogeo.distance
confrontate conlt
ole
(la "vicinanza" può essere considerata come l'uguaglianza quando viene controllata la distanza). - In
any
,or
è sempre consentito. È possibile usareand
solo per i tipi di dati che possono esprimere i controlli dell'intervallo e solo se si usano OR di AND (DNF). - In
all
, le regole sono invertite. Sono consentiti solo controlli negativi, è possibile usareand
sempre, mentreor
può essere usato solo per i controlli di intervallo espressi come AND di OR (CNF).
Anche se in pratica questi sono i tipi di filtri che è più probabile usare, è comunque utile comprenderne i limiti.
Per esempi specifici relativi ai tipi di filtri consentiti e non consentiti, vedere Come scrivere filtri validi per le raccolte.
Passaggi successivi
- Risoluzione dei problemi relativi ai filtri della raccolta OData in Azure AI Search
- Filtri in Azure AI Search
- Panoramica del linguaggio delle espressioni OData per Azure AI Search
- Informazioni di riferimento sulla sintassi delle espressioni OData per Azure AI Search
- Ricerca di documenti (API REST di Azure AI Search)