elasticsearch bool query muss mit OR kombiniert werden

181

Ich versuche derzeit, eine solr-basierte Anwendung auf elasticsearch zu migrieren.

Ich habe diese Lucene-Abfrage

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

Soweit ich weiß, handelt es sich um eine Kombination von MUST-Klauseln in Kombination mit einem booleschen ODER:

"Holen Sie sich alle Dokumente, die (foo UND Balken im Namen) ODER (foo UND Balken im Info) enthalten. Danach werden die Filter nach Bedingungsstatus = 1 gefiltert und Dokumente mit einem Bild angehoben."

Ich habe versucht, eine Bool-Abfrage mit MUST zu verwenden, aber ich kann kein boolesches ODER in must-Klauseln einfügen. Folgendes habe ich:

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
            }
          }
        }
      ]
    }
  }
}

Wie Sie sehen können, fehlen MUSS-Bedingungen für "Info".

Hat jemand eine Lösung?

Ich danke dir sehr.

** UPDATE **

Ich habe meine Elasticsearch-Abfrage aktualisiert und diese Funktionsbewertung entfernt. Mein Basisproblem besteht immer noch.

Jesse
quelle
1
Es gibt eine gute Dokumentation zum Kombinieren von ElasticSearch-Abfragen hier: elastic.co/guide/en/elasticsearch/guide/current/…
Mr.Coffee

Antworten:

422
  • ODER ist buchstabiert sollte
  • UND ist muss buchstabiert werden
  • NOR buchstabiert should_not

Beispiel:

Sie möchten alle Elemente sehen, die sind (rund UND (rot ODER blau)):

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

Sie können auch komplexere Versionen von OR ausführen. Wenn Sie beispielsweise mindestens 3 von 5 übereinstimmen möchten, können Sie unter "sollte" 5 Optionen angeben und ein "Minimum_should" von 3 festlegen.

Vielen Dank an Glen Thompson und Sebastialonso, die herausgefunden haben, wo meine Verschachtelung vorher nicht ganz richtig war.

Vielen Dank auch an Fatmajk für den Hinweis, dass "Begriff" in ElasticSearch 6 zu "Übereinstimmung" wird.

Daniel Fackrell
quelle
2
Würde das shouldin die obere Ebene ziehen boolund eine minimum_should_match: 1Arbeit einschließen ?
Sid
18
Wenn ich dieses Beispiel versuche, komme ich zurück [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. Ist das irgendwie versionabhängig?
DanneJ
24
Warum fügen sie nicht ein so einfaches Beispiel und eine Erklärung in die Dokumente ein? Das Beispiel aus der Dokumentation ist sehr verwirrend.
Nikhil Owalekar
20
Nach 6 Monaten, in denen ich die gesamte elastische Dokumentation gelesen habe, verstehe ich zum ersten Mal vollständig, wie man eine boolesche Logik implementiert. Die offizielle Dokumentation ist meiner Meinung nach nicht klar genug.
Sebastialonso
3
@Amir Welche Ungenauigkeiten kann ich für Sie beseitigen? In dem oben gezeigten Kontext ist der Standardwert minimum_should1, und das Umschließen boolführt dazu, dass diese Gruppe wahr ist, wenn mindestens ein Element übereinstimmt, und falsch, wenn keines übereinstimmt. Meine Motivation für die Erstellung dieser Antwort war, dass ich genau diese Art von Problem löste und die verfügbare Dokumentation und sogar die Antworten, die ich auf solchen Websites finden konnte, bestenfalls nicht hilfreich waren. Deshalb recherchierte ich weiter, bis ich das Gefühl hatte, einen ziemlich soliden Überblick zu haben von dem, was los war. Ich freue mich über konstruktive Hinweise, wie ich die Antwort weiter verbessern kann.
Daniel Fackrell
68

Ich habe es endlich geschafft, eine Abfrage zu erstellen, die genau das tut, was ich haben wollte:

Eine gefilterte verschachtelte boolesche Abfrage. Ich bin mir nicht sicher, warum dies nicht dokumentiert ist. Vielleicht kann mir hier jemand sagen?

Hier ist die Abfrage:

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

Bitte beachten Sie, dass es von Ihrer Dokumentenfeldanalyse und den Zuordnungen abhängt, wie name = foo intern behandelt wird. Dies kann von einem unscharfen bis zu einem strengen Verhalten variieren.

"minimum_should_match": 1 sagt, dass mindestens eine der should-Anweisungen wahr sein muss.

Diese Anweisung bedeutet, dass jedes Mal, wenn sich in der Ergebnismenge ein Dokument befindet, das has_image: 1 enthält, es um den Faktor 100 erhöht wird. Dies ändert die Reihenfolge der Ergebnisse.

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

Habt Spaß Jungs :)

Jesse
quelle
28
Heiliger Strohsack. Hat jemand eine bessere Lösung? Vielen Dank, dass Sie dies veröffentlicht haben, aber das ist absolut zu komplex, um ein logisches ODER in einer Abfrage zu erzielen.
Nackjicholson
Danke, du hast meinen Tag gerettet)
Cubbiu
3
Diese Abfrage ist nicht nur unnötig lang, sondern verwendet auch eine veraltete Syntax. @ Daniel-Fackrell Antwort sollte die akzeptierte sein.
Eric Alford
4
@EricAlford Diese Antwort aus dem Jahr 2015 basiert auf einer früheren Version von ES. Fühlen Sie sich frei, eine bessere Lösung anzubieten.
Jesse
Idee: Übernehmen / gabeln Sie ElasticSearch, schreiben Sie es benutzerfreundlich um, fügen Sie eine einfache Abfragesprache hinzu, GEWINNEN Sie! Wir brauchen nur Geld. Ich bin dabei! Wer sonst ?
Sliq
16

Auf diese Weise können Sie mehrere Bool-Abfragen mit Kibana in einer äußeren Bool-Abfrage verschachteln.

bool gibt an, dass wir boolean verwenden

Muss ist für UND

sollte ist für 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" : {} 
                                 }     
                               ]
                          }
                 }
             ]
        }
    }
}

So können Sie eine Abfrage in ES verschachteln

Es gibt mehr Typen in "bool" wie -

  1. Filter

  2. darf nicht

Niranjan Harpale
quelle
Ihre Antwort ist genau richtig, aber es ist etwas ungeschickt, es ist ein kleiner Vorschlag für Sie, wenn Sie möchten - Sie müssen es richtig bearbeiten. Wahrscheinlich gibt es Ihnen mehr wie auf diese Antwort :) Ich wünsche Ihnen einen schönen Tag.
Dhwanil Patel
5

Ich musste kürzlich auch dieses Problem lösen und nach vielen Versuchen und Irrtümern kam ich auf diese Idee (in PHP, aber direkt auf DSL abgebildet):

'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]]
        ]
    ]
]

Welche Zuordnung zu so etwas 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>

Der Schlüssel zu all dem ist die minimum_should_matchEinstellung. Ohne dies filterüberschreibt das völlig dasshould .

Hoffe das hilft jemandem!

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

In mustmüssen Sie das Abfragebedingungsarray hinzufügen, mit dem Sie arbeiten möchten, ANDund in shouldmüssen Sie die Abfragebedingung hinzufügen, mit der Sie arbeiten möchtenOR .

Sie können dies überprüfen: https://github.com/Smile-SA/elasticsuite/issues/972

Alakh Kumar
quelle
0

Wenn Sie den Standard- oder Lucene-Abfrageparser von Solr verwendet haben, können Sie ihn so gut wie immer in eine Abfragezeichenfolgenabfrage einfügen:

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)"
    }
  }
}

Möglicherweise möchten Sie jedoch eine boolesche Abfrage verwenden , wie die bereits veröffentlichte, oder sogar eine Kombination aus beiden.

Radu Gheorghe
quelle