2016-09-12 11 views
15

十分に機能するクエリがありますが、クエリのパラメータと問題のフィールドの間でlevenshteinを使用して結果を並べ替える必要があります。Elasticsearch:Levenshtein sorting

今はESでクエリを実行していて、アプリケーションでソートを行っています。今私はソートのスクリプトフィールドをテストしています。これは、基本的に、これは私は問題はこのhttp://code972.com/blog/2015/03/84-elasticsearch-one-tip-a-day-avoid-costly-scripts-at-all-costsあるこの

sortScript = String.format(EDIT_DISTANCE_GROOVY_FUNC, fullname, FULLNAME_FIELD_NAME); 

のように自分のアプリケーションに記入したテンプレートは、(%sのを確認してください)であるスクリプト

import org.elasticsearch.common.logging.*; 
ESLogger logger = ESLoggerFactory.getLogger('levenshtein_script'); 

def str1 = '%s'.split(' ').sort().join(' '); 
def str2 = doc['%s'].values.join(' '); //Needed since the field is analyzed. This will change when I reindex the data. 
def dist = new int[str1.size() + 1][str2.size() + 1] 
(0..str1.size()).each { dist[it][0] = it } 
(0..str2.size()).each { dist[0][it] = it } 
(1..str1.size()).each { i -> 
    (1..str2.size()).each { j -> 
     dist[i][j] = [dist[i - 1][j] + 1, dist[i][j - 1] + 1, dist[i - 1][j - 1] + ((str1[i - 1] == str2[j - 1]) ? 0 : 1)].min() 
    } 
} 
def result = dist[str1.size()][str2.size()] 
logger.info('Query param: ['+str1+'] | Term: ['+str2+'] | Result: ['+result+']'); 
return result; 

です。どちらが理解できる。

私の質問は、私がアプリケーションでオーバーヘッドを避けるために、私が必要とするもの(levenshteinによる結果を並べ替える)をelasticsearch内でどうやって行うことができるかということです。 これにlucene式を使用できますか?例がありますか?私はこれを達成できる他の方法がありますか?

私はElasticSearch 1.7.5をサービスとして使用しています。だから、ネイティブのプラグインは最初の解決策ではないはずです(私はそれが可能であってもわかりません、私はプロバイダに確認する必要がありますが、それが唯一実行可能な解決策であればそれだけです)。

UPDATE

だから、良い解決策は、それがhttps://www.elastic.co/blog/running-groovy-scripts-without-dynamic-scripting一度にコンパイルされるようにconfig/scriptsフォルダに保存することであろうと思われます。スクリプトは、https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.htmlを保存する代わりに索引付けすることができます。これは私のユースケースにとってはるかに便利です。これはスクリプトのコンパイルに関して同じ動作をしますか?一度しかコンパイルされませんか?

+1

唯一の要件がLevenshtein距離で結果を並べ替えることである場合は、クエリをFuzzy検索に変換できます。 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html。デフォルトでDamerau-Levenshteinを使用していますが、Classic Levenshteinに切り替えることができます – jay

+0

あなたのアプリケーションからオーバーヘッドを取り除きたいと思うとき、またはアプリケーションコード内に追加の検索ロジックを持たない場合 – jay

+0

どうにかして私の最初のコメントは私が終わる前に投稿されました - あなたはtranspositionsをfalseに設定することで古典的なLevenshteinに設定できます。詳細はこちら:https://www.elastic.co/blog/found-fuzzy-search – jay

答えて

3

GroovyはElasticsearch 5.xでは非推奨であり、Elasticsearch 6.0では削除されることに注意してください。この機能を置き換えるためにPureスクリプトを使用してみるか、または LuceneのLuceneLevenshteinDistanceを使用してネイティブJavaスクリプトを作成してください。

あなたのスクリプトは、多くのループ(Groovyヘルパーによって隠されている)が多く、潜在的にはという大きなメモリ割り当てがに追加されている点でかなり怖いです。私は大規模なパフォーマンスについて深刻な疑念を持っています。

スクリプト内に%sが存在することにも気付きました。これは、自分のコードがフィールド名を動的に置き換えることを意味します。 常にをこの目的のためにparamsに使用する必要があります。次に、このパラメータをスクリプトの変数として使用してください。これにより、フィールド名ごとにスクリプトのバージョンをコンパイルする必要がなくなります。 (ファイルベースにするためにこれを行う必要があると思います)

これはスクリプトのコンパイルと同じ動作ですか?

はい、ファイルベースのスクリプトは最も安全です(インストールするにはマシン自体にアクセスする必要があるため)。ファイルベースのスクリプトは、インラインおよびインデックスベースのスクリプトと同様にコンパイルされます。

ファイルベースのスクリプトの欠点は、すべてのノードに追加する必要があることです。そうではありませんが、すべてのノードで同じバージョンのスクリプトが必要です。つまり、更新することを選択した場合は、に新しいスクリプトを追加して置き換えるのではなく、参照することをお勧めします。

File-based scripts are picked up every 60 seconds by default

一度だけコンパイルされますか?

はい、ノードごとです。