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.