在数字时代,图像数据的管理已成为数据架构的一部分。然而,随之而来的挑战是如何有效地索引和检索这些图像文件。
这不仅涉及存储,更重要的是如何根据特定的属性(如文件名中的数字)进行排序,以便用户可以按照预期的顺序查看图像。
如下问题来自Elastic 钉钉技术交流群:
在Elasticsearch中,我们经常面对需要对数据进行排序的需求。单就排序,咱们之前有过几篇文章分析不同业务场景的排序实现。
1、Elasticsearch 8.X 如何依据 Nested 嵌套类型的某个字段进行排序?
2、Elasticsearch 线上问题排查——搞一天了,明天还要给客户解决这个问题
3、Elasticsearch 8.X:这个复杂的检索需求如何实现?
4、近期,几个典型 Elasticsearch 8.X 问题及方案探讨
5、最近几个典型 Elasticsearch 线上易出错难排查问题汇集,咱们得避免!
仅就上图中的文件名进行排序,会怎么样呢?我们构造一下数据,执行一下看。
POST /my_photos/_bulk
{ "index" : { "_id" : "1" } }
{ "photo_id" : "photo1.jpg", "upload_date" : "2024-02-01T10:00:00" }
{ "index" : { "_id" : "2" } }
{ "photo_id" : "photo2.jpg", "upload_date" : "2024-02-01T10:05:00" }
{ "index" : { "_id" : "3" } }
{ "photo_id" : "photo12.jpg", "upload_date" : "2024-02-01T10:10:00" }
{ "index" : { "_id" : "4" } }
{ "photo_id" : "photo111.jpg", "upload_date" : "2024-02-01T10:15:00" }
### 执行检索
GET /my_photos/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"photo_id.keyword": {
"order": "asc"
}
}
]
}
召回结果,同图中后半部分结果一致。
结果并没有达到预期。
而可行的解决方案,还得从文件名入手才可以。图像文件名包含数字,需要根据这些数字进行排序,这才是根本!
我们采用两种不同的解决方案来尝试解决这个问题。
第一种:基于脚本排序。
第二种:复杂问题简单化,预处理管道拆分出数值字段,基于数值排序。
使用 _script 进行排序是一种灵活的方法,它允许我们编写自定义脚本来解析文件名并提取排序依据的数字。
GET /my_photos/_search
{
"query": {
"match_all": {}
},
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"source": """
String photoId = doc['photo_id.keyword'].value;
if (photoId == null) return 0;
Matcher m = /[0-9]+/.matcher(photoId);
if (m.find()) {
return Integer.parseInt(m.group(0));
} else {
return 0;
}
"""
},
"order": "asc"
}
}
}
执行结果已经有序:
上述脚本基于正则表达式从photo_id字段中查找并提取出数字,如果找到就返回这个数字,如果找不到就返回0。
这样的操作对于根据数字对文档进行排序非常有用。
虽然这种方法非常强大,但它可能会因为脚本的执行而影响查询性能,数据量巨大的时候,咱们要慎用!
除了上面的方案,另一种方法是在索引数据时使用Ingest管道预处理图像文件名。
这样可以在数据索引时就提取出文件名中的数字并存储在一个专门的字段中。
这种方法的好处是可以显著提高排序的效率,因为数字已经被预处理并作为数值类型存储,使得排序操作更加快速。
就是开头咱们提到的复杂问题简单化。
PUT _ingest/pipeline/extract_photo_number
{
"description": "Extracts numbers from photo_id and stores it in photo_number",
"processors": [
{
"grok": {
"field": "photo_id",
"patterns": ["%{NUMBER:photo_number:int}"]
}
}
]
}
DELETE my_photos_20240201
### 创建索引的时候,记得指定上面创建好的预处理管道。
### 新增的字段photo_number,和上面的预处理管道获取的字段一一对应。
PUT my_photos_20240201
{
"settings": {
"default_pipeline":"extract_photo_number"
},
"mappings": {
"properties": {
"photo_id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"photo_number": {
"type": "long"
},
"upload_date": {
"type": "date"
}
}
}
}
### 批量写入数据
POST /my_photos_20240201/_bulk
{ "index" : { "_id" : "1" } }
{ "photo_id" : "photo1.jpg", "upload_date" : "2024-02-01T10:00:00" }
{ "index" : { "_id" : "2" } }
{ "photo_id" : "photo2.jpg", "upload_date" : "2024-02-01T10:05:00" }
{ "index" : { "_id" : "3" } }
{ "photo_id" : "photo12.jpg", "upload_date" : "2024-02-01T10:10:00" }
{ "index" : { "_id" : "4" } }
{ "photo_id" : "photo111.jpg", "upload_date" : "2024-02-01T10:15:00" }
### 执行检索和排序
POST my_photos_20240201/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"photo_number": {
"order": "asc"
}
}
]
}
官方文档参考:
https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html
执行结果如下:
与脚本排序对比可以看出:
本文探讨了在Elasticsearch中对包含数字的图像文件名进行排序的挑战及其解决方案。
在选择哪种方案时,我们需要考虑实际需求和系统资源。
如果对性能有较高要求,预处理方案更为合适。但如果需求复杂多变,可能需要脚本排序的灵活性。
我更想跟大家探讨的是:未来的数据建模应考虑到数据的索引和查询模式。
例如,如果我们知道将来需要按照文件名中的数字排序,那么在设计数据模型时就应该考虑到这一点,以便于实现高效的查询。
前置考虑得越充分,后面就越省事!
本文分享自 铭毅天下Elasticsearch 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!