业务场景中,特别是审核相关的一些场景,经常会有对数据进行抽取评估的需求。抽取的规则需要尽可能的平均。
当数据量小的时候,用mysql的 order by rand() 即可实现,但当数据量非常大的时候,该方法就不是很适用了,会非常的慢。
此时我们就可以借助其他的一些工具,比如elasticsearch (如果你业务中已经使用了的话,否则可以考虑其他的技术方案)
如果运用elasticsearch来实现随机抽取的目的呢?跟mysql的 order by rand() 采用一样的逻辑,elasticsearch 也支持自定义的排序规则。
如下, 设置排序规则为 (doc[‘_id’].value + params.random_salt).hashCode(), params.random_salt 为自己设置的加密盐,如我这里设置的是 random_salt = md5(time())
{
"_source":{
"include":[
"id"
]
},
"sort":{
"_script":{
"script":{
"inline":"(doc['_id'].value + params.random_salt).hashCode()",
"params":{
"random_salt":"50715bab076c6c3376556c85c8236723"
}
},
"type":"number",
"order":"asc"
}
},
"size":10,
"query":{
"bool":{
"filter":[
{
"range":{
"create_time":{
"gte":1609731331,
"lte":1611135233
}
}
}
]
}
}
}
以上检索条件会查询出满足条件的10条随机记录,这是运用了search, 如果想要抽取特别多的数据的话,scroll也同样适用。当然你也可以选择其他的排序规则,只要确保该规则计算的结果尽可能的随机即可。
注意:如果是想要多页的获取数据的话,必须保证多页的检索条件的sort是同样的,否则就会出现检索出相同的数据(因为每次都是按照不同的排序规则排序,获取该排序规则上,该页的数据)。当然,如果只是想要抽取少量的数据,无需多页获取的话,也可以直接使用 “script”: “Math.random()” 来获取随机数据。
{
"_script":{
"script":"Math.random()",
"type":"number",
"order":"asc"
}
}


