您好,请教个问题。我现在有2千多万的手机号码信息保存在es里。5个分片,3个节点。 现在的需求是将后八位相同的号码匹配到一起,重新放到一个index里。组成情侣号。方便后续查询情侣号列表。 我目前的做法是用scroll查询出一万条,多线程循环一万条中的每条,去全库扫描---但是这种做法一分钟才能处理一万条。您有什么新的思路没。 死磕Elasticsearch知识星球 https://t.zsxq.com/Iie66qV
问题补充:索引存储了手机号,同时存储了插入时间。
后八位相同的号码即为情侣号。
举例:
13011112222
13511112222
13711112222
缺点:script效率低一些
Elasticsearch自带reindex
功能就是实现索引迁移的,当然自定义读写也可以实现。
考虑到数据量级千万级别,全量聚合不现实。
可以,基于时间切片,取出最小时间戳、最大时间戳,根据数据总量和时间范围划分出时间间隔。
举例:以30分钟为单位切割千万级数据。
terms聚合只返回对应:key,value值,默认value值由高到低排序。
key:代表手机号后8位,value:代表相同后8位的数据量。
举例:查询“11112222”,返回2.1列表的三个手机号。
优点:无需额外字段存储。
缺点:效率低。
优点:效率高。
缺点:需要独立存储的后8位字段。
只包含非业务的有效必要字段。
(1)插入时间戳字段 insert_time, date类型。
由:ingest默认生成,不手动添加,提高效率。
(2)手机号字段 phone_number, text和keyword类型。
(3)后8位手机号字段 last_eight_number, keyword类型。
只聚合和排序用,不检索。
ingest pipeline的核心功能可以理解为写入前数据的ETL。
而:insert_time可以自动生成、last_eight_number可以基于phone_number提取。
定义如下:
# 0.create ingest_pipeline of insert_time and last_eight_number
PUT _ingest/pipeline/initialize
{
"description": "Adds insert_time timestamp to documents",
"processors": [
{
"set": {
"field": "_source.insert_time",
"value": "{{_ingest.timestamp}}"
}
},
{
"script": {
"lang": "painless",
"source": "ctx.last_eight_number = (ctx.phone_number.substring(3,11))"
}
}
]
}
两个索引:
由于两索引Mapping结构一样,使用模板管理会更为方便。
定义如下:
# 1.create template of phone_index and phone_couple_index
PUT _template/phone_template
{
"index_patterns": "phone_*",
"settings": {
"number_of_replicas": 0,
"index.default_pipeline": "initialize",
"index": {
"max_ngram_diff": "13",
"analysis": {
"analyzer": {
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer"
}
},
"tokenizer": {
"ngram_tokenizer": {
"token_chars": [
"letter",
"digit"
],
"min_gram": "1",
"type": "ngram",
"max_gram": "11"
}
}
}
}
},
"mappings": {
"properties": {
"insert_time":{
"type":"date"
},
"last_eight_number":{
"type":"keyword"
},
"phone_number": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
},
"analyzer": "ngram_analyzer"
}
}
}
}
PUT phone_index
PUT phone_couple_index
采用模拟数据,实际业务会有所区别。
POST phone_index/_bulk
{"index":{"_id":1}}
{"phone_number" : "13511112222"}
{"index":{"_id":2}}
{"phone_number" : "13611112222"}
{"index":{"_id":3}}
{"phone_number" : "13711112222"}
{"index":{"_id":4}}
{"phone_number" : "13811112222"}
{"index":{"_id":5}}
{"phone_number" : "13844248474"}
{"index":{"_id":6}}
{"phone_number" : "13866113333"}
{"index":{"_id":7}}
{"phone_number" : "15766113333"}
模拟数据显示,有两组情侣号。
如前所述,聚合的目的是:提取出情侣号(>=2
)的手机号或对应id。
GET phone_index/_search
{
"size": 0,
"query": {
"range": {
"insert_time": {
"gte": 1584871200000,
"lte": 1584892800000
}
}
},
"aggs": {
"last_aggs": {
"terms": {
"field": "last_eight_number",
"min_doc_count": 2,
"size": 10,
"shard_size": 30
},
"aggs": {
"sub_top_hits_aggs": {
"top_hits": {
"size": 100,
"_source": {
"includes": "phone_number"
},
"sort": [
{
"phone_number.keyword": {
"order": "asc"
}
}
]
}
}
}
}
}
}
注意:
基于3.3 取出的满足条件的id进行跨索引迁移。
POST _reindex
{
"source": {
"index": "phone_index",
"query": {
"terms": {
"_id": [
1,
2,
3,
4,
6,
7
]
}
}
},
"dest": {
"index": "phone_couple_index"
}
}
注意:实际业务需要考虑数据规模,划定轮询时间间隔区间。
建议:按照2.3章节的流程图执行。
第3节的实战一把实际是基于基础数据都写入ES了再做的处理。
核心的操作都是基于Elasticsearch完成的。
试想一下,这个环节如果提前是不是更合理呢?
数据图如下所示:
这样,Elasticsearch只干它最擅长的事情,剩下的工作前置交给消息队列完成。
本文就提出问题做了详细的阐述和实践,用到Elasticsearch 模板、Ingest、reindex等核心知识点和操作,给线上业务提供了理论参考。
大家对本文有异议或者有更好的方案,欢迎留言交流。
本文分享自 铭毅天下Elasticsearch 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有