在ElasticSearch中随机文档

39

有没有一种方法可以从 Elasticsearch 索引中获取真正随机的样本?即从索引中检索任何文档的查询,其概率为 1/N(其中N是当前索引的文档数)?

作为跟进问题:如果所有文档都具有某些数字字段 s,是否有一种获取加权随机采样文档的方法,即获取文档 i 的概率与值 s_i 相等,即 s_i / sum(s_j for j in index)

5个回答

74

我知道这是一个老问题,但现在可以使用random_score

{
   "size": 1,
   "query": {
      "function_score": {
         "functions": [
            {
               "random_score": {
                  "seed": "1477072619038"
               }
            }
         ]
      }
   }
}

对我来说,它处理大约200万个文档非常快。

我使用当前时间戳作为种子,但您可以使用任何您喜欢的种子。最好是如果您使用相同的种子,您将获得相同的结果。因此,您可以使用用户会话ID作为种子,所有用户将具有不同的顺序。


2
对于ES的更新版本,请参考以下链接:https://www.elastic.co/guide/en/elasticsearch/reference/5.4/query-dsl-function-score-query.html#function-random - Ian Kemp
注意:默认情况下,如果您不提供种子,则使用当前时间戳。此外,我发现如果让ES使用自己的种子(当前时间戳),查询速度会快20倍(这是在一个非常大的集群上,6秒对比150秒)。 - Robin Zimmerman

7

在1.3.1版本及以下的Elasticsearch中,我所知道的从索引中获取随机文档的唯一方法是使用脚本:

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

您可以使用该脚本根据记录的某个字段进行加权处理。
未来可能会添加更复杂的功能,但您可能需要向ES团队请求。

1
无法使用此种子。将分组n个文档,并具有相同的得分,其中n是分片大小。 - sudeepdino008
无痛脚本 Math.random() 返回一个包括 0 和 1 在内的值吗? - Praneeth Kumar

6
您可以在使用function_score查询时使用random_score。
{
    "size":1,
    "query": {
        "function_score": {
            "functions": [
                {
                    "random_score":  {
                        "seed": 11
                    }
                }
            ],
            "score_mode": "sum",
        }
    }
}

不好的一面是这会给每个文档随机打分,然后排序文档并返回第一个。我不知道是否有智能工具可以只选择一个随机文档。


4
NEST之道:
var result = _elastic.Search<dynamic>(s => s
        .Query(q => q
        .FunctionScore(fs => fs.Functions(f => f.RandomScore())
        .Query(fq => fq.MatchAll()))));

原始查询方式:

 GET index-name/_search
    "size": 1,
    "query": {
        "function_score": {
                "query" : { "match_all": {} },
               "random_score": {}
        }
    }
}

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接