2016-08-07 12 views
7

Ich habe die folgende Abfrage, um Unschärfe zu meiner Suche hinzuzufügen. Ich stelle jedoch fest, dass die Übereinstimmungsabfrage nicht die Reihenfolge der Wörter in der Suchzeichenfolge berücksichtigt, wie dies bei der Übereinstimmungsphrase der Fall ist. Allerdings kann ich Matchphrase nicht erhalten, um mir Ergebnisse mit Unschärfe zu geben. Gibt es eine Möglichkeit zu sagen, ob die Reihenfolge und die Entfernung zwischen Wörtern übereinstimmen sollen?Elasticsearch Fuzzy Phrasen

{ 
    "query": { 
     "match": { 
      "content": { 
       "query": "some search terms like this", 
       "fuzziness": 1, 
       "operator": "and" 
      } 
     } 
    } 
} 

Antwort

7

Schließlich herausgefunden, dass ich eine Kombination von span Abfragen verwendet werden benötigt, die eine ausgezeichnete Menge an Feinabstimmung zu Unschärfen und Slop geben. Ich brauchte eine Funktion hinzuzufügen manuell meine Sätze tokenize und in einem programmatisch auf die „Klauseln“ Array hinzufügen:

{"query": 
{ 
    "span_near": { 
    "clauses": [ 
     { 
     "span_multi": { 
      "match": { 
      "fuzzy": { 
       "content": { 
       "fuzziness": "2", 
       "value": "word" 
       } 
      } 
      } 
     } 
     }, 
     { 
     "span_multi": { 
      "match": { 
      "fuzzy": { 
       "content": { 
       "fuzziness": "2", 
       "value": "another" 
       } 
      } 
      } 
     } 
     }     
    ], 
    "slop": 1, 
    "in_order": "true" 
1

@econgineer Excellent Beitrag.

Ich wollte dies für eine ES-Abfrage, um versuchen wir arbeiten - aber ich bin zu faul, um die JSON-Daten zu halten tun ....

Ich denke, dieser Code funktioniert ... seltsam verursacht es jq zu beschweren, aber Elasticsearch Arbeit ....

import json 
import pprint 
from collections import defaultdict 
nested_dict = lambda: defaultdict(nested_dict) 
query=nested_dict() 
query['span_near']['clauses']=list() 
query['slop']='1' 
query['in_order']="true" 


words=['what','is','this'] 
for w in words: 
    nest = nested_dict() 
    nest["span_multi"]["match"]["fuzzy"]["msg"]["fuzziness"]["value"]=w 
    nest["span_multi"]["match"]["fuzzy"]["msg"]["fuzziness"]["fuzziness"]="2" 
    json.dumps(nest) 
    query['span_near']['clauses'].append(json.loads(json.dumps(nest))) 


pprint.pprint(json.loads(json.dumps(query))) 

Wenn Sie die Ausgabe von

cat t2.json | tr "\'" "\"" | jq '.' 

verschönern sollten Sie sehen etwas wie

{ 
    "in_order": "true", 
    "slop": "1", 
    "span_near": { 
    "clauses": [ 
     { 
     "span_multi": { 
      "match": { 
      "fuzzy": { 
       "msg": { 
       "fuzziness": { 
        "fuzziness": "2", 
        "value": "what" 
       } 
       } 
      } 
      } 
     } 
     }, 
     { 
     "span_multi": { 
      "match": { 
      "fuzzy": { 
       "msg": { 
       "fuzziness": { 
        "fuzziness": "2", 
        "value": "is" 
       } 
       } 
      } 
      } 
     } 
     }, 
     { 
     "span_multi": { 
      "match": { 
      "fuzzy": { 
       "msg": { 
       "fuzziness": { 
        "fuzziness": "2", 
        "value": "this" 
       } 
       } 
      } 
      } 
     } 
     } 
    ] 
    } 
} 

Und dann ES abfragen es

curl --silent My_ES_Server:9200:/INDEX/_search -d @t2.json 

Vielen Dank für die erste Führung nur normal ist, ich hoffe, dass jemand anderes diese Verwendung finden.

+0

Wie kann man einen der machen 'optional sein span_multi'? – perrohunter

0

In der Tat eine ausgezeichnete Frage und Antwort. Ich bin überrascht, dass diese "Fuzzy-Phrase-Match" keine Unterstützung aus der Box hat.

Hier ist ein getesteter NodeJS-Code, der den Fuzzy-Phrasen-Match (Multiklausel) -Abfrageblock im Kontext einer Multi-Suche (Msearch) erzeugt, der aber bei einer einzigen Suche genauso funktionieren sollte.

Verbrauch:

let queryBody = []; 
client.msearch({ 
    body: queryBody 
}) 

queryBody.push({ index: 'YOUR_INDEX' }); 
queryBody.push(createESFuzzyPhraseQueryBlock('YOUR PHRASE', 'YOUR_FIELD_NAME', 2)); // 2 <- fuzziness 

Funktionen:

const createESFuzzyPhraseClauseBlock = (word, esFieldName, fuzziness) => { 
    let clauseBlock = JSON.parse(
     `{ 
      "span_multi": { 
       "match": { 
        "fuzzy": { 
         "${esFieldName}": { 
          "fuzziness": "${fuzziness}", 
          "value": "${word}" 
         } 
        } 
       } 
      } 
     }`); 

    return clauseBlock; 
}; 


const createESFuzzyPhraseQueryBlock = (phrase, esFieldName, fuzziness) => { 
    let clauses = []; 

    let words = phrase.split(' '); 
    words.forEach(word => clauses.push(createESFuzzyPhraseClauseBlock(word, esFieldName, fuzziness))); 

    let queryBlock = 
     { 
      "query": 
       { 
        "span_near": { 
         "clauses": clauses, 
         "slop": 1, 
         "in_order": "true" 
        } 
       } 
     }; 

    return queryBlock; 
}; 
+0

Wie können Sie eines der 'span_multi' optional machen? – perrohunter