2017-08-21 2 views
0

Ich habe diese einfachen Dokumente:Elasticsearch benutzerdefinierte Sortierung/Hinzufügen Filterklauseln Partituren

{ 
    id : 1, 
    book_ids : [2,3], 
    collection_ids : ['a','b'] 
}, 
{ 
    id : 2, 
    book_ids : [1,2] 
} 

Wenn ich diese Filterabfrage ausführen, wird es beiden Dokumente gefunden:

{ 
    bool: { 
     filter: [ 
      { 
       bool: { 
        should: [ 
         { 
          bool: { 
           must_not: { 
            exists: { 
             field: 'book_ids' 
            } 
           } 
          } 
         }, 
         { 
          bool: { 
           filter: { 
            term: { 
             book_ids: 2 
            } 
           } 
          } 
         } 
        ] 
       } 
      }, 
      { 
       bool: { 
        should: [ 
         { 
          bool: { 
           must_not: { 
            exists: { 
             field: 'collection_ids' 
            } 
           } 
          } 
         }, 
         { 
          bool: { 
           filter: { 
            term: { 
             collection_ids: 'a' 
            } 
           } 
          } 
         } 
        ] 
       } 
      } 
     ] 
    } 
} 

Die Ich möchte diese Dokumente sortieren, und ich möchte, dass die erste (ID: 1) zuerst zurückgegeben wird, weil sie sowohl dem book_ids Wert als auch den collection_ids Werten entspricht ded.

Eine einfache Art Klausel wie diese funktioniert nicht:

[ 
    'book_ids', 
    'collection_ids' 
] 

weil es erste Dokument 2 aufgrund der book_ids Array ersten Wert zurück.

Bearbeiten: Dies ist ein vereinfachtes Beispiel für das Problem, mit dem ich konfrontiert bin, die N solche Klauseln in der Klausel muss. Außerdem gibt es eine Reihenfolge zwischen den Klauseln, wie ich versucht habe, mit dem sort Snippet zu reflektieren: Ergebnisse, die der ersten Klausel (book_ids) entsprechen, sollten vor Ergebnissen erscheinen, die der zweiten Klausel (collection_ids) entsprechen. Ich suche wirklich nach einer Art von SQL-Sortieroperation, bei der ich nur den übereinstimmenden Wert des Feldarrays berücksichtigen würde. Eine praktikable Option könnte darin bestehen, jeder term-Klausel abnehmende constant_scores entsprechend der erwarteten Sortierreihenfolge zuzuweisen, und ES würde diese Sub-Scores zur Berechnung des Endergebnisses summieren müssen. Aber ich kann nicht herausfinden, wie es geht oder ob es überhaupt möglich ist.

Bonus Frage: Gibt es irgendeine Möglichkeit für ElasticSearch, eine Art neues Dokument mit nur den übereinstimmenden Werten zurückzugeben? Hier ist, was ich erwarten würde, als Reaktion auf die oben Filterabfrage:

{ 
    id : 1, 
    book_ids : [2], 
    collection_ids : ['a'] 
}, 
{ 
    id : 2, 
    book_ids : [2] 
} 

Antwort

0

Ich glaube, du hast Recht über die ständige Punktzahl Idee. Ich glaube, Sie es wie folgt tun:

{ 
    query: { 
    bool: { 
     must: [ 
     { 
      bool: { 
      should: [ 
       { 
       bool: { 
        must_not: { 
        exists: { 
         field: 'book_ids' 
        } 
        } 
       } 
       }, 
       { 
       constant_score: { 
        filter: { 
        term: { 
         book_ids: 2 
        } 
        }, 
        boost: 100 
       } 
       } 
      ] 
      } 
     }, 
     { 
      bool: { 
      should: [ 
       { 
       bool: { 
        must_not: { 
        exists: { 
         field: 'collection_ids' 
        } 
        } 
       } 
       }, 
       { 
       constant_score: { 
        filter: { 
        term: { 
         collection_ids: 'a' 
        } 
        }, 
        boost: 50 
       } 
       } 
      ] 
      } 
     } 
     ] 
    } 
    } 
} 

ich glaube, das einzige, was Sie wurden mit konstanter Punktzahl fehlt, war wahrscheinlich nur, dass die Top-Level-Abfrage must sein muss, nicht filter. (Es gibt keine Bewertung für Filter, alle Bewertungen sind 0.)

Eine Alternative wäre, den Filter in eine function_score Abfrage setzen (aber lassen Sie es als Filter), und berechnen Sie dann die Punktzahl, wie Sie wollen (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html)

In Bezug auf die Bonusfrage ist es möglich, wenn Sie ein Skriptfeld verwenden, um ein neues Feld wie gewünscht zu filtern und hinzuzufügen (https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-script-fields.html), aber das ist nicht direkt möglich. Es ist wahrscheinlich einfacher und sinnvoller, diese Filterung nach dem Erhalt des Ergebnisses durchzuführen, es sei denn, Sie haben sehr lange Listen in Ihren Werten.

+0

Hallo @ Dshockley, danke, dass Sie sich die Zeit genommen haben, sich das anzuschauen. Um Ihnen zu antworten: Ja, dieses Verhalten war beabsichtigt und ich denke, dass ich dieses Umschreiben nicht verwenden kann, da ich mehr als 2 solcher Klauseln habe. Ich werde das in meiner Frage klären.Außerdem gibt es wirklich eine Sortierreihenfolge für mein Problem, Ergebnisse, die mit der ersten Klausel ('' 'book_ids''') übereinstimmen, sollten vor den Ergebnissen erscheinen, die der zweiten Klausel (' '' collection_ids''') entsprechen. Mit der von Ihnen vorgeschlagenen Lösung glaube ich nicht, dass dies der Fall ist. Und ich muss wirklich auf N solche Klauseln verallgemeinern. – Mathiou

+0

Ah ich sehe - es ist jetzt viel klarer - ich habe meine Antwort bearbeitet, um zu zeigen, wie ich denke, dass du es mit constant_score machen kannst. – dshockley

+0

Ich denke, es ist verallgemeinerbar zu so vielen Bedingungen wie Sie wollen, aber Sie müssen die Boost-Werte sorgfältig auswählen (und verwenden Sie "erklären": True, um herauszufinden, was los ist, wenn es sich nicht wie erwartet verhält) – dshockley

Verwandte Themen