web-dev-qa-db-ja.com

ランダムな順序とページネーションElasticsearch

この問題 には、ランダムな順序の再作成を可能にするオプションのシードを使用した注文の機能リクエストがあります。

ランダムに並べられた結果をページ分割できるようにする必要があります。 Elasticsearch 0.19.1でこれをどのように行うことができますか?

ありがとう。

30
Yeggeps

一意のフィールド(idなど)のハッシュ関数とランダムなソルトを使用してソートできます。結果の真のランダム度に応じて、次のような原始的なことを実行できます。

{
  "query" : { "query_string" : {"query" : "*:*"} },
  "sort" : {
    "_script" : { 
        "script" : "(doc['_id'].value + salt).hashCode()",
        "type" : "number",
        "params" : {
            "salt" : "some_random_string"
        },
        "order" : "asc"
    }
  }
}

または洗練されたもの

{
  "query" : { "query_string" : {"query" : "*:*"} },
  "sort" : {
    "_script" : { 
        "script" : "org.elasticsearch.common.Digest.md5Hex(doc['_id'].value + salt)",
        "type" : "string",
        "params" : {
            "salt" : "some_random_string"
        },
        "order" : "asc"
    }
  }
}

2番目の例では、よりランダムな結果が生成されますが、多少遅くなります。

このアプローチでフィールド_idを保存する必要があります。そうでない場合、クエリはNullPointerExceptionで失敗します。

32
imotov

これは上記の両方の答えよりもかなり速く、シードをサポートします:

curl -XGET 'localhost:9200/_search' -d '{
  "query": {
    "function_score" : {
      "query" : { "match_all": {} },
      "random_score" : {}
    }
  }
}';

参照: https://github.com/elasticsearch/elasticsearch/issues/117

56
Nariman

Imotovからの良い解決策。

これははるかに単純なものであり、ドキュメントプロパティに依存する必要はありません。

{
  "query" : { "query_string" : {"query" : "*:*"} },
  "sort" : {
    "_script" : { 
        "script" : "Math.random()",
        "type" : "number",
        "params" : {},
        "order" : "asc"
    }
  }
}

次のような範囲を設定する場合:

{
  "query" : { "query_string" : {"query" : "*:*"} },
  "sort" : {
    "_script" : { 
        "script" : "Math.random() * (myMax - myMin) + myMin",
        "type" : "number",
        "params" : {},
        "order" : "asc"
    }
  }
}

maxとminを適切な値に置き換えます。

21
DavidGOrtega

私はimotovが提案したものとは少し異なる方法で解決しました。クライアントが複数あるので、すべてのクライアントにソルト文字列を取り巻くロジックを実装したくありませんでした。

モデルにはすでにrandomized_keyがありました。また、すべてのリクエストで順序がランダムである必要はなかったので、ランダムなキーを毎晩更新するようにスケジュールされたジョブを作成し、Elasticssearchのそのフィールドでソートしました。

3
Yeggeps

ええと、私はこれを行うことを検討していましたが、上記のすべてのアプローチは、比較的単純なものに対しては少し「複雑すぎる」ように見えました。だから私は「精神的に行く」必要がなくても完璧に機能する代替案を思いついた

最初に_countクエリを実行してから、それを "Start"およびRand(0、$ count)と組み合わせます

例えば.

JSONArray = array of json to send to ElasticSearch
$total_results = $ElasticSearchClient->count(JSONArray)
$start = Rand(0, $total_results)
JSONArray['body']['from'] = $start;
$ElasticSearchClient->search(JSONArray);

上記の例の前提:

  • あなたはPHPを実行しています
  • また、PHPクライアントを使用しています

しかし、PHPでこれを行う必要はありません。このアプローチはどのような例でも機能します。

0
Andy