la query bool di elasticsearch si combina con OR


181

Attualmente sto provando a migrare un'applicazione basata su solr a elasticsearch.

Ho questa domanda lucene

(( 
    name:(+foo +bar) 
    OR info:(+foo +bar) 
)) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)

Per quanto ho capito, questa è una combinazione di clausole MUST combinate con booleani OR:

"Ottieni tutti i documenti contenenti (foo AND barra nel nome) OPPURE (foo AND barra nelle informazioni). Dopo quel filtro i risultati per condizione state = 1 e aumenta i documenti che hanno un'immagine."

Ho cercato di utilizzare una query booleata con MUST ma non riesco a ottenere booleana O nelle clausole must. Ecco cosa ho:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "foo"
          }
        },
        {
          "match": {
            "name": "bar"
          }
        }
      ],
      "must_not": [],
      "should": [
        {
          "match": {
            "has_image": {
              "query": 1,
              "boost": 100
            }
          }
        }
      ]
    }
  }
}

Come puoi vedere, DEVONO mancare le condizioni per "informazioni".

Qualcuno ha una soluzione?

Grazie mille.

** AGGIORNARE **

Ho aggiornato la mia query elasticsearch e mi sono sbarazzato di quel punteggio di funzione. Il mio problema di base esiste ancora.


1
C'è una buona documentazione sulla combinazione di query ElasticSearch qui: elastic.co/guide/en/elasticsearch/guide/current/…
Mr.Coffee

Risposte:


426
  • O è scritto dovrebbe
  • E è scritto il mosto
  • NOR è scritto should_not

Esempio:

Vuoi vedere tutti gli elementi che sono (rotondo AND (rosso OR blu)):

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {"shape": "round"}
                },
                {
                    "bool": {
                        "should": [
                            {"term": {"color": "red"}},
                            {"term": {"color": "blue"}}
                        ]
                    }
                }
            ]
        }
    }
}

Puoi anche fare versioni più complesse di OR, ad esempio se vuoi abbinare almeno 3 su 5, puoi specificare 5 opzioni in "should" e impostare un "minimo_sformato" di 3.

Grazie a Glen Thompson e Sebastialonso per aver scoperto dove la mia nidificazione non era abbastanza prima.

Grazie anche a Fatmajk per aver sottolineato che "termine" diventa "match" in ElasticSearch 6.


2
Tirando il shouldlivello superiore boole includendo minimum_should_match: 1un'opera?
Sid,

18
Quando provo questo esempio torno indietro [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. Questa versione dipende in qualche modo?
DanneJ,

26
Perché non aggiungono un esempio e una spiegazione così semplici nei documenti! L'esempio della documentazione è molto confuso.
Nikhil Owalekar,

21
Dopo 6 mesi, leggendo tutta la documentazione Elastica, questa è la prima volta che capisco completamente come implementare la logica booleana. La documentazione ufficiale manca di chiarezza secondo me.
Sebastialonso,

3
@Amir Quali imprecisioni posso ripulire per te? Nel contesto mostrato sopra, il valore predefinito minimum_shouldè 1 e, se lo si racchiude, il boolrisultato è che quel gruppo è vero se almeno un elemento corrisponde, falso se nessuno corrisponde. La mia motivazione per creare questa risposta era che stavo risolvendo esattamente questo tipo di problema, e la documentazione disponibile e persino le risposte che potevo trovare su siti come questo erano al massimo inutili, quindi ho continuato a fare ricerche finché non ho sentito di avere una comprensione abbastanza solida di quello che stava succedendo. Accolgo volentieri eventuali suggerimenti costruttivi su come migliorare ulteriormente la risposta.
Daniel Fackrell,

69

Finalmente sono riuscito a creare una query che fa esattamente quello che volevo avere:

Una query booleana nidificata filtrata. Non sono sicuro del perché questo non sia documentato. Forse qualcuno qui può dirmelo?

Ecco la query:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "term": {
                "state": 1
              }
            }
          ]
        }
      },
      "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "name": "foo"
                    }
                  },
                  {
                    "match": {
                      "name": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "info": "foo"
                    }
                  },
                  {
                    "match": {
                      "info": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            }
          ],
          "minimum_should_match": 1
        }
      }    
    }
  }
}

In pseudo-SQL:

SELECT * FROM /test/object
WHERE 
    ((name=foo AND name=bar) OR (info=foo AND info=bar))
AND state=1

Si prega di tenere presente che dipende dall'analisi del campo del documento e dalle mappature delle modalità di gestione interna di name = foo. Questo può variare da un comportamento sfocato a un comportamento rigoroso.

"minimum_should_match": 1 dice che almeno una delle istruzioni should deve essere vera.

Questa affermazione significa che ogni volta che c'è un documento nel set di risultati che contiene has_image: 1 viene potenziato dal fattore 100. Ciò cambia l'ordinamento dei risultati.

"should": [
  {
    "match": {
      "has_image": {
        "query": 1,
        "boost": 100
      }
    }
   }
 ]

Divertitevi ragazzi :)


28
Merda santa. Qualcuno ha una soluzione migliore? Grazie per aver pubblicato questo, ma è assolutamente troppa complessità per ottenere un OR logico in una query.
nackjicholson,

grazie, mi hai salvato la giornata)
cubbiu,

3
Questa query non solo è inutilmente lunga, ma utilizza una sintassi deprecata. La risposta di @ daniel-fackrell dovrebbe essere quella accettata.
Eric Alford,

4
@EricAlford Questa risposta del 2015 si basa su una versione precedente di ES. Sentiti libero di fornire una soluzione migliore.
Jesse,

1
Idea: sostituisci / buca ElasticSearch, riscrivilo in modo intuitivo, aggiungi un linguaggio di query semplice, VINCI! Abbiamo solo bisogno di finanziamenti. Sono dentro! Chi altro ?
Sliq,

16

Ecco come puoi nidificare più query bool in una query bool esterna usando Kibana,

bool indica che stiamo usando booleano

il must è per AND

dovrebbe è per OR

GET my_inedx/my_type/_search
{
    "query" : {
       "bool": {             //bool indicates we are using boolean operator
            "must" : [       //must is for **AND**
                 {
                   "match" : {
                         "description" : "some text"  
                     }
                 },
                 {
                    "match" :{
                          "type" : "some Type"
                     }
                 },
                 {
                    "bool" : {          //here its a nested boolean query
                          "should" : [  //should is for **OR**
                                 {
                                   "match" : {
                                       //ur query
                                  }
                                 },
                                 { 
                                    "match" : {} 
                                 }     
                               ]
                          }
                 }
             ]
        }
    }
}

Ecco come è possibile nidificare una query in ES

Ci sono più tipi in "bool" come -

  1. Filtro

  2. non devi


La tua risposta è esattamente giusta, ma è un po 'goffa, è un piccolo suggerimento per te se vuoi - devi modificarlo correttamente. Probabilmente ti dà più like su questa risposta :) Buona giornata.
Dhwanil Patel,

6

Di recente ho dovuto risolvere anche questo problema, e dopo MOLTE prove ed errori mi sono inventato questo (in PHP, ma è mappato direttamente al DSL):

'query' => [
    'bool' => [
        'should' => [
            ['prefix' => ['name_first' => $query]],
            ['prefix' => ['name_last' => $query]],
            ['prefix' => ['phone' => $query]],
            ['prefix' => ['email' => $query]],
            [
                'multi_match' => [
                    'query' => $query,
                    'type' => 'cross_fields',
                    'operator' => 'and',
                    'fields' => ['name_first', 'name_last']
                ]
            ]
        ],
        'minimum_should_match' => 1,
        'filter' => [
            ['term' => ['state' => 'active']],
            ['term' => ['company_id' => $companyId]]
        ]
    ]
]

Che si associa a qualcosa del genere in SQL:

SELECT * from <index> 
WHERE (
    name_first LIKE '<query>%' OR
    name_last LIKE '<query>%' OR
    phone LIKE  '<query>%' OR
    email LIKE '<query>%'
)
AND state = 'active'
AND company_id = <query>

La chiave in tutto questo è l' minimum_should_matchimpostazione. Senza questo il filtertotale ha la precedenza sul should.

Spero che questo aiuti qualcuno!


0
$filterQuery = $this->queryFactory->create(QueryInterface::TYPE_BOOL, ['must' => $queries,'should'=>$queriesGeo]);

In mustè necessario aggiungere la matrice condizione di query che si desidera lavorare con ANDe shouldè necessario aggiungere la condizione di query che si desidera lavorare conOR .

Puoi controllare questo: https://github.com/Smile-SA/elasticsuite/issues/972


0

Se stavi usando il parser di query predefinito o Lucene di Solr, puoi praticamente metterlo sempre in una query di stringa di query:

POST test/_search
{
  "query": {
    "query_string": {
      "query": "(( name:(+foo +bar) OR info:(+foo +bar)  )) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)"
    }
  }
}

Detto questo, potresti voler utilizzare una query booleana , come quella che hai già pubblicato, o anche una combinazione delle due.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.