一、场景说明

索引中有几千万的数据,现在需要每次查询随机抽样返回10条数据,怎么实现?


二、实现方式

DSL语句执行如下:

GET myIndex/_search
{
  "from": 0,
  "size": 20,
  "timeout": "10s",
  "sort": {
    "_script": {
      "script": "Math.random()",
      "type": "number",
      "order": "asc"
    }
  }
}

java代码实现:

private void randomSort(SearchSourceBuilder sourceBuilder){
    Script script = new Script("Math.random()");
    ScriptSortBuilder sortBuilder = new ScriptSortBuilder(script, ScriptSortBuilder.ScriptSortType.NUMBER);
    sourceBuilder.sort(sortBuilder);
}

三、注意事项

实际开发过程中发现,如果对索引中的全量数据进行随机抽样查询是非常消耗查询性能的。

我遇到的情况:
生产环境上,8千万多万数据的索引进行随机抽样查询耗时5s,这种查询速度显然是不能接受的。
在这里插入图片描述

优化改进:
sort排序是针对匹配的所有数据进行排序,而8000多万数据的随机排序,显然非常耗时。
我们可以在查询条件中增加一些随机查询条件,比如主键id的随机前缀匹配,数据产生时间的随机范围匹配,
从而减轻随机匹配的性能损耗。

由于我的索引数据中id的前缀都是在0~9,所以我在每次查询时,先生成0~9的随机数,然后去匹配主键id做前缀匹配。

{
  "query": {
    "wildcard": {
      "id": {
        "value": "1*"
      }
    }
  }
  ,"sort":[{"_script":{"script":{"source":"Math.random()","lang":"painless"},"type":"number","order":"asc"}}]
}

在这里插入图片描述
可以发现,每次随机查询匹配的数据量total的直显著下降,消耗的查询时间took也明显降低,完全能满足生产要求。


总结

本文主要介绍了ES中如何实现随机抽样查询,并强调了随机抽样查询的性能损耗问题以及对应的解决方案。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐