2014-04-02 12 views
11

I miei filtri sono raggruppati in categorie. Vorrei recuperare i documenti in cui un documento può corrispondere a qualsiasi filtro in una categoria, ma se sono impostate due (o più) categorie, il documento deve corrispondere a qualsiasi filtro in TUTTE le categorie.Come eseguire i filtri AND e OR annidati in ElasticSearch?

Se scritto in pseudo-SQL sarebbe:

SELECT * FROM Documents WHERE (CategoryA = 'A') AND (CategoryB = 'B' OR CategoryB = 'C') 

Ho provato filtri nidificati in questo modo:

{ 
    "sort": [{ 
     "orderDate": "desc" 
    }], 
    "size": 25, 
    "query": { 
     "match_all": {} 
    }, 
    "filter": { 
     "and": [{ 
      "nested": { 
       "path":"hits._source", 
       "filter": { 
        "or": [{ 
         "term": { 
          "progress": "incomplete" 
         } 
        }, { 
         "term": { 
          "progress": "completed" 
         } 
        }] 
       } 
      } 
     }, { 
      "nested": { 
       "path":"hits._source", 
       "filter": { 
        "or": [{ 
         "term": { 
          "paid": "yes" 
         } 
        }, { 
         "term": { 
          "paid": "no" 
         } 
        }] 
       } 
      } 
     }] 
    } 
} 

Ma evidentemente io non capisco la sintassi ES. È sulla strada giusta o devo usare un altro filtro?

+0

la risposta alla domanda: '' or'' con '' term'' può essere fatto più facilmente con [termini] (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms- filter.html). e l'impostazione predefinita per [bool] (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html) è '' and''. qualcosa lungo '' filter.bool.must: [{terms: progress: ["incomplete", "complete"]}. {terms: paid: ["yes", "no"]}] '' potrebbe funzionare? – cfrick

+0

query/filtri nidificati vengono utilizzati per matrici/elenchi (dipende dalla lingua con cui si ha familiarità, ad esempio 'a = [{'b': 1}, {'c': 2}])'. Potresti scrivere un esempio di uno dei tuoi documenti? Ciò aiuterebbe – Diolor

+0

cfrick mi ha guidato sulla strada giusta. Ho annidato un sacco di filtri 'termini' all'interno di un filtro 'e', ​​e sembra soddisfare le mie esigenze. – MHTri

risposta

3

Anche se non ho compreso completamente la tua struttura, questo potrebbe essere quello che ti serve.

Devi pensare ad albero. Crei un bool in cui devi (= e) soddisfare i bool incorporati. Ogni controllo incorporato se il campo non esiste o altrimenti (utilizzando dovrebbe invece di deve) il campo deve (termini qui) essere uno dei valori nell'elenco.

Non sono sicuro se esiste un modo migliore e non conosciamo le prestazioni.

{ 
    "sort": [ 
     { 
      "orderDate": "desc" 
     } 
    ], 
    "size": 25, 
    "query": { 
     "query": {   # 
      "match_all": {} # These three lines are not necessary 
     },     # 
     "filtered": { 
      "filter": { 
       "bool": { 
        "must": [ 
         { 
          "bool": { 
           "should": [ 
            { 
             "not": { 
              "exists": { 
               "field": "progress" 
              } 
             } 
            }, 
            { 
             "terms": { 
              "progress": [ 
               "incomplete", 
               "complete" 
              ] 
             } 
            } 
           ] 
          } 
         }, 
         { 
          "bool": { 
           "should": [ 
            { 
             "not": { 
              "exists": { 
               "field": "paid" 
              } 
             } 
            }, 
            { 
             "terms": { 
              "paid": [ 
               "yes", 
               "no" 
              ] 
             } 
            } 
           ] 
          } 
         } 
        ] 
       } 
      } 
     } 
    } 
} 
+2

Questo non è corretto. 'must' e' should' non sono alias per 'and' e' or'. Hanno funzionalità diverse (anche se ci sono similitudini concettualmente) –

8

Questo dovrebbe essere esso (tradotto dal dato pseudo-SQL)

{ 
    "sort": [ 
     { 
     "orderDate": "desc" 
     } 
    ], 
    "size": 25, 
    "query": 
    { 
     "filtered": 
     { 
      "filter": 
      { 
       "and": 
       [ 
        { "term": { "CategoryA":"A" } }, 
        { 
         "or": 
         [ 
          { "term": { "CategoryB":"B" } }, 
          { "term": { "CategoryB":"C" } } 
         ] 
        } 
       ] 
      } 
     } 
    } 
} 

Mi rendo conto che non stai menzionare sfaccettature, ma solo per ragioni di completezza:

Si potrebbe anche usare un filter come base (come hai fatto tu) invece di un filtered query (come ho fatto io). Il json risultante è quasi identico all'essere differenza:

  • una query filtrata filtrerà entrambi i principali risultati e sfaccettature
  • un filtro filtra soltanto i principali risultati non le sfaccettature.

Infine, filtri nidificati (che si è tentato di utilizzare) non si riferiscono a 'filtri di nidificazione' come ti sembrava di credere, ma legato a filtrare sulla annidati-documenti (genitore-figlio)

non
Problemi correlati