2012-10-01 9 views
17

Ich bin auf der Suche nach einer Möglichkeit zu tun genau Array-Treffern in elastische Suche. Sagen wir, das sind meine Dokumente:Exakte Suche in Array-Objekttyp mit elasticsearch

{"id": 1, "categories" : ["c", "d"]} 
{"id": 2, "categories" : ["b", "c", "d"]} 
{"id": 3, "categories" : ["c", "d", "e"]} 
{"id": 4, "categories" : ["d"]} 
{"id": 5, "categories" : ["c", "d"]} 

Gibt es eine Möglichkeit für alle, die das Dokument zu suchen haben genau die Kategorien „c“ und „d“ (Artikel 1 und 5), nicht mehr oder weniger?

Als Bonus: Die Suche nach „eine dieser“ Kategorien sollte nach wie vor auch möglich sein (zum Beispiel könnten Sie für „c“ suchen und erhalten 1, 2, 3 und 5)

Jede kluge Weise zu dieses Problem angehen?

Antwort

19

Wenn Sie einen diskreten, bekannten Satz von Kategorien haben, könnten Sie eine Bool-Abfrage verwenden:

"bool" : { 
    "must" : { 
     "terms" : { "categories" : ["c", "d"], 
      minimum_should_match : 2 
     } 
    }, 
    "must_not" : { 
     "terms" : { "categories" : ["a", "b", "e"], 
      minimum_should_match : 1 
     } 
    } 
} 

Ansonsten wahrscheinlich der einfachste Weg, dies zu erreichen, denke ich, wird ein anderes Feld als eine Portion zu speichern Kategorien Schlüsselwort.

{"id": 1, "categories" : ["c", "d"], "categorieskey" : "cd"} 

So ähnlich. Dann könnte man leicht mit einem Begriff Abfrage Abfrage für genau die gewünschten Ergebnisse, wie:

term { "categorieskey" : "cd" } 

Und man konnte noch suchen nicht ausschließlich, as;

term { "categories" : "c" } 

für zwei Kategorien abfragen, die einfach genug vorhanden sein müssen, ist beides, aber dann von allen anderen potentiellen Kategorien verhindert vorhanden ist ein bisschen schwieriger ist. Du könntest es wahrscheinlich tun. Wahrscheinlich möchten Sie eine Abfrage schreiben, um Datensätze mit beiden zu finden, und dann einen Filter anwenden, der alle Datensätze mit anderen als den angegebenen Kategorien löscht. Es ist nicht wirklich eine Art von Suche, für die Lucene wirklich ausgelegt ist, meines Wissens.

Ehrlich gesagt, habe ich ein bisschen Mühe, mit einem guten Filter zu kommen, um hier zu verwenden. Möglicherweise benötigen Sie einen Skriptfilter oder Sie können die Ergebnisse filtern, nachdem sie abgerufen wurden.

+1

lustig, das ist genau das, was ich ihm gesagt :) – phoet

+0

@phoet Sie so klug;) – paukul

+0

@femtoRgon es Ihnen danken! Leider sind das schlechte Nachrichten :) – paukul

1

Ich habe eine Lösung für unseren Anwendungsfall gefunden, die zu funktionieren scheint. Es beruht auf zwei Filtern und dem Wissen, mit wie vielen Kategorien wir übereinstimmen wollen. Wir verwenden einen Terms-Filter und einen Skriptfilter, um die Größe des Arrays zu überprüfen. In diesem Beispiel ähnelt MarketBasketList Ihrem Eintrag in der Kategorie.

{ 
    "query": { 
    "bool": { 
     "must": [ 
     { 
      "match": { 
      "siteId": 4 
      } 
     }, 
     { 
      "match": { 
      "marketBasketList": { 
       "query": [ 
       10, 
       11 
       ], 
       "operator": "and" 
      } 
      } 
     } 
     ] 
    }, 
    "boost": 1, 
    "filter": { 
     "and": { 
     "filters": [ 
      { 
      "script": { 
       "script": "doc['marketBasketList'].values.length == 2" 
      } 
      }, 
      { 
      "terms": { 
       "marketBasketList": [ 
       10, 
       11 
       ], 
       "execution": "and" 
      } 
      } 
     ] 
     } 
    } 
    } 
} 
Verwandte Themen