业务场景中,特别是审核相关的一些场景,经常会有对数据进行抽取评估的需求。抽取的规则需要尽可能的平均。
当数据量小的时候,用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" } }