web-dev-qa-db-fra.com

Ordre aléatoire et pagination Elasticsearch

Dans ce numéro Est une demande de fonctionnalité permettant de commander avec une valeur de départ facultative permettant de recréer un ordre aléatoire.

Je dois être capable de paginer des résultats ordonnés au hasard. Comment cela pourrait-il être fait avec Elasticsearch 0.19.1?

Merci.

24
Yeggeps

Vous pouvez trier à l'aide d'une fonction de hachage d'un champ unique (par exemple, id) et d'un sel aléatoire. En fonction du résultat réellement aléatoire, vous pouvez faire quelque chose d'aussi primitif que:

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

ou quelque chose d'aussi sophistiqué que

{
  "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"
    }
  }
}

Le deuxième exemple produira plus de résultats aléatoires mais sera un peu plus lent. 

Pour que cette approche fonctionne, le champ _id doit être enregistré. Sinon, la requête échouera avec NullPointerException

31
imotov

Cela devrait être considérablement plus rapide que les deux réponses ci-dessus et prend en charge le semis:

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

Voir: https://github.com/elasticsearch/elasticsearch/issues/1170

55
Nariman

Bonne solution de imotov.

Voici quelque chose de beaucoup plus simple et vous n'avez pas besoin de compter dans une propriété de document: 

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

si vous voulez définir une plage qui ressemblerait à quelque chose comme:

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

remplacer le max et le min par vos propres valeurs.

21
DavidGOrtega

J'ai fini par résoudre le problème légèrement différemment de ce que suggérait imotov. Comme j'ai plusieurs clients, je ne voulais pas implémenter la logique entourant la chaîne de sel sur chacun d'entre eux.

J'ai déjà eu une randomized_key sur le modèle. Comme je n'avais pas besoin que l'ordre soit aléatoire pour chaque demande, j'ai donc programmé un travail pour mettre à jour la clé aléatoire chaque nuit, puis trié par champ dans Elasticssearch.

3
Yeggeps

Eh bien, je cherchais à faire cela et toutes les approches ci-dessus semblaient un peu "trop ​​compliquées" pour quelque chose qui devrait être relativement simple. Donc, je suis venu avec une alternative qui fonctionne parfaitement bien sans la nécessité de "devenir mental"

J'effectue d'abord une requête _count puis la combine avec "Démarrer" et Rand (0, $ count)

par exemple.

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);

Hypothèses pour l'exemple ci-dessus:

  • Vous utilisez PHP
  • Vous utilisez également le PHP Client

Mais vous n’avez PAS BESOIN de faire cela avec PHP, cette approche fonctionnerait avec n’importe quel exemple. 

0
Andy