2017-08-03 2 views
0

Ich bin Neuling in ES und suche auf einem Datensatz von 100k Daten. Hier ist meine Mapping und JSON Einstellung, mit denen ich meine Daten indiziert:ElasticSearch Query Optimierung - Java API

setings.json

{ 
    "index": { 
     "analysis": { 
      "tokenizer": { 
       "ngram_tokenizer": { 
        "type": "ngram", 
        "min_gram": 3, 
        "max_gram": 10 
       } 
      }, 
      "analyzer": { 
       "ngram_tokenizer_analyzer": { 
        "type": "custom", 
        "tokenizer": "ngram_tokenizer" 
       } 
      } 
     } 
    } 
} 

mappings.json

{ 
    "product": { 
     "properties": { 
      "name": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "description": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "vendorModelNumber": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "brand": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "specifications": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "upc": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "storeSkuId": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      }, 
      "modelNumber": { 
       "type": "string", 
       "analyzer": "ngram_tokenizer_analyzer", 
       "store": true 
      } 
     } 
    } 
} 

Ich brauche Dokumente auf allen Feldern Abfrage basierend erwähnt nach einer bestimmten Priorität. Hier ist meine Abfrage nach allen Datensätzen zu suchen.

BoolQueryBuilder query = QueryBuilders.boolQuery(); 
int boost = 7; 

for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("name", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("description", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("modelNumber", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("vendorModelNumber", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("storeSkuId", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("upc", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
boost--; 
for (String str : dataSplit) { 
    query.should(QueryBuilders.wildcardQuery("brand", "*" + str.toLowerCase() + "*").boost(boost)); 
} 
client.prepareSearch(index).setQuery(query).setSize(200).setExplain(true).execute().actionGet(); 

Die Abfrage tut mir bei der Suche Daten helfen und funktioniert gut, aber mein Problem ist, dass es viel Zeit in Anspruch nimmt, da ich Wildcard Abfrage verwende. Kann jemand bitte helfen, diese Abfrage zu optimieren, oder mir bei der Suche nach der am besten geeigneten Suchanfrage für meine Suche helfen? TIA.

+0

Warum verwenden Sie in erster Linie Platzhalter? Wenn Sie einen Ngram-Tokenizer mit 3+ verwenden, sollte eine normale Übereinstimmungsabfrage mit Eingaben funktionieren, die länger als 2 Zeichen sind. Oder was ist der Grund für den Ngram Tokenizer überhaupt? Eine Nebenbemerkung; Mit diesem Analysator (wie definiert) werden Ihre Abfragen zwischen Groß- und Kleinschreibung unterschieden. Möglicherweise beabsichtigt, aber ziemlich ungewöhnlich. – Slomo

+0

Dank @Slomo Sie haben Recht. Ich hätte keine Wildcards mit Ngram verwenden sollen. kann ich es case insensitive machen? und mit Ngram sollte ich mit term Query oder Match abfragen, was ist der optimale Weg? Entschuldigung, wenn das keine vernünftige Frage ist :) – DivyaMenon

Antwort

1

Zunächst einmal, lassen Sie mich zuerst die einfache Frage beantworten: behandeln Groß- und Kleinschreibung. Wenn Sie einen benutzerdefinierten Analysator definieren, können Sie verschiedene Filter hinzufügen, die auf jeden Token angewendet werden, nachdem die Eingabe vom Tokenizer verarbeitet wurde.

{ 
"index": { 
    "analysis": { 
     "tokenizer": { 
      "ngram_tokenizer": { 
       "type": "ngram", 
       "min_gram": 3, 
       "max_gram": 10 
      } 
     }, 
     "analyzer": { 
      "ngram_tokenizer_analyzer": { 
       "type": "custom", 
       "tokenizer": "ngram_tokenizer", 
       "filter": [ 
        "lowercase", 
        ... 
       ] 
      } 
     } 
    } 
} 

Wie Sie sehen, gibt es einen bestehenden Klein Filter, der alle Token einfach verwandelt Fall zu senken. Ich empfehle dringend, auf die documentation zu verweisen. Es gibt einen Los dieser Token-Filter.


Jetzt der kompliziertere Teil: NGram Tokenizer. Noch einmal, für ein tieferes Verständnis möchten Sie vielleicht docs lesen. Aber mit Bezug auf Ihr Problem, Ihre tokenizer werden im Wesentlichen hinsichtlich der Länge 3 bis 10 einrichten, bedeutet das den Text

I am an example TEXT. 

Wird im Grunde eine Menge von Token erstellen. zu zeigen, um nur ein paar:

  • Größe 3: "Ich a", "Uhr", "bin", ..., "TEX", "EXT"
  • Größe 4: "Ich bin", "bin", "bin ein", ..., "TEX", "TEXT".
  • Größe 10: "Ich bin ein Ex", ...

Sie erhalten die Idee. (Der Token-Filter mit Kleinbuchstaben würde diese Token jetzt klein schreiben)

Unterschied zwischen Match- und Termabfrage: Matchabfragen werden analysiert, Termabfragen hingegen nicht. Das bedeutet, dass Ihre Übereinstimmungsabfragen mehreren Begriffen entsprechen können. Beispiel: Sie stimmen mit exam" überein.

Dies würde 3 Begriffe in der Tat übereinstimmen: exa, xam und exam.

Dies hat Einfluss auf das Ergebnis der Spiele. Je mehr Treffer, desto höher der Punktestand. In manchen Fällen ist es erwünscht, in anderen nicht.

Eine Termabfrage wird nicht analysiert, was bedeutet, exam würde übereinstimmen, aber nur einen Begriff (exam natürlich). Da es jedoch nicht analysiert wird, ist es auch nicht klein, was bedeutet, dass Sie das selbst tun müssen. Exam würde nie übereinstimmen, weil es keinen Ausdruck mit Großbuchstaben in Ihrem Index gibt, wenn Sie den Tokenfilter in Kleinbuchstaben verwenden.

Nicht sicher über Ihren Anwendungsfall. Aber ich habe das Gefühl, dass Sie den Begriff Query tatsächlich verwenden können (oder wollen). Aber beachten Sie, es gibt keine Begriffe in Ihrem Index mit einer Größe größer als 10. Weil das ist, was Ihr Ngram-Tokenizer tut.

/EDIT:

Etwas wert in Bezug auf Spiel-Abfragen unter Hinweis darauf, und der Grund, warum Sie vielleicht Begriffe verwenden: Einige Spiel Anfragen wie Simple auch mple von example übereinstimmen.

+0

Tnx viel @Slomo für die detaillierte Erklärung. wird meinen Code verfeinern und wird auch den Doc durchlaufen. :) – DivyaMenon

+0

Also angenommen, ich muss mehrere Werte in mehreren Feldern suchen, Bool mit Match-Abfrage wäre eine gute Option, oder? – DivyaMenon

+1

@DivyaMenon Sie können. Oder vielleicht können Sie auch die [multiMatch] (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html) verwenden, wo Sie auch in der Lage sein sollten Gewicht Felder. Vielleicht würde ein konkretes Suchbeispiel mit erwarteten Ergebnissen helfen, Ihre Frage zu beantworten. – Slomo