Query ES per abbinare tutti gli elementi nell'array
Quindi ho ottenuto questo documento con un array nidificato che voglio filtrare con questa query.
Voglio che ES restituisca tutti i documenti in cui tutti gli elementi hanno modifiche = 0 e solo quello. Se il documento ha anche un solo elemento nell'elenco con una modifica = 1, viene scartato.
C'è un modo per ottenerlo partendo dalla query che ho già scritto? O dovrei usare uno script invece?
DOCUMENTI:
{
"id": "abc",
"_source" : {
"trips" : [
{
"type" : "home",
"changes" : 0
},
{
"type" : "home",
"changes" : 1
}
]
}
},
{
"id": "def",
"_source" : {
"trips" : [
{
"type" : "home",
"changes" : 0
},
{
"type" : "home",
"changes" : 0
}
]
}
}
DOMANDA:
GET trips_solutions/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"id": {
"value": "abc"
}
}
},
{
"nested": {
"path": "trips",
"query": {
"range": {
"trips.changes": {
"gt": -1,
"lt": 1
}
}
}
}
}
]
}
}
}
RISULTATO ATTESO:
{
"id": "def",
"_source" : {
"trips" : [
{
"type" : "home",
"changes" : 0
},
{
"type" : "home",
"changes" : 0
}
]
}
}
Versione Elasticsearch: 7.6.2
Ho già letto queste risposte ma non mi hanno aiutato: https://discuss.elastic.co/t/how-to-match-all-item-in-nested-array/163873 ElasticSearch: come interrogare un array nidificato esatto
Risposte
Prima di tutto, se filtri per id: abc, ovviamente non sarai in grado di tornare id: defindietro.
In secondo luogo, a causa della natura dei nestedcampi che sono trattati come documenti secondari separati, non è possibile interrogare per tutti quelli tripsche hanno changesuguale a 0 - la connessione tra i singoli viaggi è persa e loro "non si conoscono".
Quello che puoi fare è restituire solo i viaggi che corrispondono alla tua query nidificata utilizzando inner_hits:
GET trips_solutions/_search
{
"_source": "false",
"query": {
"bool": {
"must": [
{
"nested": {
"inner_hits": {},
"path": "trips",
"query": {
"term": {
"trips.changes": {
"value": 0
}
}
}
}
}
]
}
}
}
La soluzione più semplice è quindi salvare dinamicamente queste informazioni nidificate su un oggetto genitore come discusso qui e utilizzando la query intervallo / termine sull'array risultante.
MODIFICARE:
Ecco come lo fai utilizzando copy_toil livello superiore del documento:
PUT trips_solutions
{
"mappings": {
"properties": {
"trips_changes": {
"type": "integer"
},
"trips": {
"type": "nested",
"properties": {
"changes": {
"type": "integer",
"copy_to": "trips_changes"
}
}
}
}
}
}
trips_changessarà un array di numeri - presumo che siano numeri interi ma sono disponibili più tipi .
Quindi sincronizzare alcuni documenti:
POST trips_solutions/_doc
{"trips":[{"type":"home","changes":0},{"type":"home","changes":1}]}
POST trips_solutions/_doc
{"trips":[{"type":"home","changes":0},{"type":"home","changes":0}]}
E infine interrogando:
GET trips_solutions/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "trips",
"query": {
"term": {
"trips.changes": {
"value": 0
}
}
}
}
},
{
"script": {
"script": {
"source": "doc.trips_changes.stream().filter(val -> val != 0).count() == 0"
}
}
}
]
}
}
}
Si noti che per prima cosa filtriamo normalmente utilizzando il termine nidificato query per restringere il nostro contesto di ricerca (gli script sono lenti, quindi questo è utile). Quindi controlliamo se ci sono valori diversi da zero changesnelle modifiche di livello superiore accumulate e rifiutiamo quelle applicabili.