2013-01-24 16 views
6

Sto riscontrando problemi nell'utilizzo di ElasticSearch per la mia applicazione java. Mi spiego, ho una mappatura, che è qualcosa di simile:ElasticSearch: ordinamento per i valori dei documenti nidificati

{ 
"products": { 
    "properties": { 
     "id": { 
      "type": "long", 
        "ignore_malformed": false 
     }, 
     "locations": { 
      "properties": { 
       "category": { 
        "type": "long", 
        "ignore_malformed": false 
       }, 
       "subCategory": { 
        "type": "long", 
        "ignore_malformed": false 
       }, 
       "order": { 
        "type": "long", 
        "ignore_malformed": false 
       } 
      } 
     }, 
... 

Quindi, come potete vedere, ho ricevere un elenco di prodotti, che sono composti di posizioni. Nel mio modello, queste posizioni sono il prodotto di tutte le categorie. Significa che un prodotto può essere in 1 o più categorie. In ciascuna di questa categoria, il prodotto ha un ordine, che è l'ordine che il cliente desidera mostrare.

Ad esempio, un prodotto di diamanti può avere un primo posto in Gioielli, ma il terzo posto in Donna (i miei esempi non sono così logici ^^). Quindi, quando clicco su Gioielli, voglio mostrare questi prodotti, ordinati per località field.order in questa specifica categoria.

Per il momento, quando cerco tutti i prodotti in una categoria specifica per la risposta elasticsearch che ricevo è qualcosa di simile:

{"id":5331880,"locations":[{"category":5322606,"order":1}, 
{"category":5883712,"subCategory":null,"order":3}, 
{"category":5322605,"subCategory":6032961,"order":2},....... 

E 'possibile ordinare questo prodotti, dall'elemento locations.order per la categoria specifica che sto cercando? Ad esempio, se sto interrogando la categoria 5322606, voglio che venga preso l'ordine 1 per questo prodotto.

Grazie mille in anticipo! Cordiali saluti, Olivier.

risposta

9

Prima una correzione della terminologia: in Elasticsearch, "genitore/figlio" si riferisce a documenti completamente separati, in cui il documento figlio indica il documento padre. Genitore e figli sono memorizzati sullo stesso frammento, ma possono essere aggiornati indipendentemente.

Con il tuo esempio sopra, ciò che stai cercando di ottenere può essere fatto con i documenti nested.

Attualmente il campo locations è di type:"object". Ciò significa che i valori in ogni località vengono appiattite a cercare qualcosa di simile:

{ 
    "locations.category": [5322606, 5883712, 5322605], 
    "locations.subCategory": [6032961], 
    "locations.order": [1, 3, 2] 
} 

In altre parole, i campi "sub" vengono appiattiti in campi a più valori, che non è di alcuna utilità per voi, perché ci Nessuna correlazione tra category: 5322606 e order: 1.

Tuttavia, se si cambia locations essere type:"nested" poi internamente indicizza ogni postazione come un documento separato, il che significa che ogni posizione può essere interrogato in maniera indipendente, usando l'apposito nestedquery e filter.

Per impostazione predefinita, la query nested restituirà una _score sulla base di quanto bene ogni posizione corrisponde, ma nel tuo caso si vuole restituire il valore più alto del campo order da figli di corrispondenza. Per fare ciò, dovrai utilizzare una query custom_score.

Quindi partiamo con la creazione dell'indice con la mappatura appropriata:

curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1' -d ' 
{ 
    "mappings" : { 
     "products" : { 
     "properties" : { 
      "locations" : { 
       "type" : "nested", 
       "properties" : { 
        "order" : { 
        "type" : "long" 
        }, 
        "subCategory" : { 
        "type" : "long" 
        }, 
        "category" : { 
        "type" : "long" 
        } 
       } 
      }, 
      "id" : { 
       "type" : "long" 
      } 
     } 
     } 
    } 
} 
' 

L'indice che il tuo esempio doc:

curl -XPOST 'http://127.0.0.1:9200/test/products?pretty=1' -d ' 
{ 
    "locations" : [ 
     { 
     "order" : 1, 
     "category" : 5322606 
     }, 
     { 
     "order" : 3, 
     "subCategory" : null, 
     "category" : 5883712 
     }, 
     { 
     "order" : 2, 
     "subCategory" : 6032961, 
     "category" : 5322605 
     } 
    ], 
    "id" : 5331880 
} 
' 

E ora possiamo cercare utilizzando le query abbiamo discusso in precedenza :

curl -XGET 'http://127.0.0.1:9200/test/products/_search?pretty=1' -d ' 
{ 
    "query" : { 
     "nested" : { 
     "query" : { 
      "custom_score" : { 
       "script" : "doc[\u0027locations.order\u0027].value", 
       "query" : { 
        "constant_score" : { 
        "filter" : { 
         "and" : [ 
          { 
           "term" : { 
           "category" : 5322605 
           } 
          }, 
          { 
           "term" : { 
           "subCategory" : 6032961 
           } 
          } 
         ] 
        } 
        } 
       } 
      } 
     }, 
     "score_mode" : "max", 
     "path" : "locations" 
     } 
    } 
} 
' 

Nota: le virgolette singole all'interno dello script sono state classificate come \u0027 per aggirare il quoting della shell. Lo script in realtà assomiglia a questo: "doc['locations.order'].value"

Se si guarda alla _score dai risultati, si può vedere che ha usato il valore order dalla corrispondenza location:

{ 
    "hits" : { 
     "hits" : [ 
     { 
      "_source" : { 
       "locations" : [ 
        { 
        "order" : 1, 
        "category" : 5322606 
        }, 
        { 
        "order" : 3, 
        "subCategory" : null, 
        "category" : 5883712 
        }, 
        { 
        "order" : 2, 
        "subCategory" : 6032961, 
        "category" : 5322605 
        } 
       ], 
       "id" : 5331880 
      }, 
      "_score" : 2, 
      "_index" : "test", 
      "_id" : "cXTFUHlGTKi0hKAgUJFcBw", 
      "_type" : "products" 
     } 
     ], 
     "max_score" : 2, 
     "total" : 1 
    }, 
    "timed_out" : false, 
    "_shards" : { 
     "failed" : 0, 
     "successful" : 5, 
     "total" : 5 
    }, 
    "took" : 9 
} 
+0

Ciao DrTech, Grazie mille per la risposta, che è esattamente quello che stavo cercando. Ho modificato la mia mappatura e funziona bene. Tuttavia, non so come fare la richiesta custom_score con l'API java, e non c'è nulla di menzionato a riguardo. Potresti aiutarmi con quello? Grazie ancora! È davvero molto apprezzato. Buon fine settimana. Olivier –

+0

Quindi dovresti accettare la risposta :) – DrTech

+0

Ho aspettato di sapere se hai qualche feedback sull'API java. Ho appena accettato la risposta poiché è ben spiegata e la mia comprensione ora è molto meglio. Hai qualche conoscenza con l'API java? Grazie mille in anticipo. –

Problemi correlati