2012-10-01 11 views
17

Sto cercando un modo per fare esatte corrispondenze di matrice nella ricerca elastica. Diciamo che questi sono i miei documenti:Ricerca esatta nel tipo di oggetto array usando 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"]} 

Esiste un modo per cercare per tutti del documento che hanno esattamente categorie "C" e "D" (documenti 1 e 5), non di più o di meno?

Come bonus: Ricerca di "una di queste" categorie dovrebbe essere ancora possibile, nonché (per esempio si potrebbe cercare "c" e ottenere 1, 2, 3 e 5)

Un modo intelligente per affrontare questo problema?

risposta

19

Se si dispone di una discreta, nota serie di categorie, è possibile utilizzare una query bool:

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

In caso contrario, probabilmente il modo più semplice per ottenere questo risultato, credo, è quello di memorizzare un altro campo che serve come un categorie di parola chiave.

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

Qualcosa del genere. Poi si potrebbe facilmente interrogare con una query termine per esattamente i risultati desiderati, come:

term { "categorieskey" : "cd" } 

E si potrebbe ancora cercare non esclusivamente, come;

term { "categories" : "c" } 

Interrogazione per due categorie che devono entrambi essere presenti è abbastanza facile, ma poi impedendo altre eventuali categorie potenziali di essere presente è un po 'più difficile. Potresti farlo, probabilmente. Probabilmente vorresti scrivere una query per trovare i record con entrambi, quindi applicare un filtro per eliminare tutti i record con categorie diverse da quelle specificate. Non è davvero una specie di ricerca che Lucene è davvero progettata per gestire, per quanto ne so.

Onestamente, sto avendo un po 'di problemi con un buon filtro da usare qui. Potrebbe essere necessario un filtro di script, oppure è possibile filtrare i risultati dopo che sono stati recuperati.

+1

divertente, questo è esattamente quello che gli ho detto :) – phoet

+0

@phoet voi in modo intelligente;) – paukul

+0

@femtoRgon grazie! sfortunatamente questa è una brutta notizia :) – paukul

1

Ho trovato una soluzione per il nostro caso di utilizzo che sembra funzionare. Si basa su due filtri e sulla conoscenza di quante categorie vogliamo confrontare. Utilizziamo un filtro termini e un filtro script per verificare la dimensione dell'array. In questo esempio, marketBasketList è simile alla voce delle categorie.

{ 
    "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" 
      } 
      } 
     ] 
     } 
    } 
    } 
} 
Problemi correlati