大家好,我是Edison。
上一篇:基于Term和全文的ES查询
结构化数据
结构化搜索(Structured Search)是指对结构化数据的搜索,那么,什么数据是结构化的呢?
ES中日期、布尔类型和数字都是结构化的。
另外,文本也可以是结构化的:
-
比如彩色笔可以有离散的颜色集合:红、蓝、绿等;
-
一个博客也可能被标记了一些标签:分布式、搜索、架构等;
-
电商网站上的商品都有UPCs(通用产品码)或其他的唯一标识,它们都需要遵从严格规定的、结构化的格式。
结构化搜索
结构化搜索(Structured Search)是指对结构化数据的搜索,那么我们接下来就看看如何做结构化搜索。在ES中对结构化数据进行匹配,主要使用term查询。
NOTE:对于文本的全文查询,主要使用match哟。
首先,我们先添加一些测试数据,以便后续场景中的示例。请注意里面这些测试数据的结构,后面两条并没有date字段哟。
DELETE products POST /products/_bulk { "index":{"_id":1}} { "productID": "XHDK-A-1293-#fJ3", "price":10, "avaliable":true, "date":"2024-04-01"} { "index":{"_id":2}} { "productID": "KDKE-B-9947-#kL5", "price":20, "avaliable":true, "date":"2023-04-01"} { "index":{"_id":3}} { "productID": "J0DL-X-1937-#pV7", "price":30, "avaliable":true } { "index":{"_id":4}} { "productID": "QQPX-R-3956-#aD8", "price":30, "avaliable":false }
场景1:针对布尔、时间、日期和数字类型的结构化数据
这类数据有精确的格式,可以直接对这些格式进行逻辑操作,比如 比较数字或时间的范围,或判定两个值的大小。
(1)布尔值
// 对布尔值进行查询(有算分) // ES会返回3条记录 POST /products/_search { "profile": "true", "query": { "term": { "avaliable": true } } }
ES返回结果:3条记录,有计算分
从之前的学习中,我们知道,可以使用constant_score转成filtering,进而避免算分,提高性能。
// 对布尔值进行查询(使用constant_score,无算分) // ES会返回3条记录 POST /products/_search { "profile": "true", "query": { "constant_score": { "filter": { "term": { "avaliable": true } } } } }
ES返回结果:3条记录,没有计算分
(2)数字和日期Range
// 数字Range查询价格>=30 并 <=40的记录 POST /products/_search { "profile": "true", "query": { "constant_score": { "filter": { "range": { "price": { "gte": 30, "lte": 40 } } } } } } // 日期Range查询:查询近一年的记录 // y 年 M 月 w 周 d 天 // H / h 小时 m 分钟 s 秒 POST /products/_search { "profile": "true", "query": { "constant_score": { "filter": { "range": { "date": { "gte": "now-1y" } } } } } }
(3)处理空值
// exists 可以过滤不包含某字段的记录 POST /products/_search { "profile": "true", "query": { "constant_score": { "filter": { "exists": { "field": "date" } } } } }
场景2:针对结构化文本做部分匹配 或 精确匹配
为了演示,我们插入两个测试数据来看看处理多值的情况:
POST /movies/_bulk { "index":{"_id":1}} { "title": "Father of the Bridge Part II", "year": 1995, "genre": "Comedy" } { "index":{"_id":2}} { "title": "Dave", "year": 1993, "genre": ["Comedy", "Romance"] }
可以看到,第二条数据的genre字段包含了多个值,是一个集合字段。
然后,我们可以通过term+ keyword来处理多值字段的查询:查找genre属于Comedy(喜剧)的记录。这里需要注意的是,term查询的逻辑关系是包含而不是完全相等,所以它做的是部分匹配。
// 查询包含单个值的记录 POST /movies/_search { "query": { "constant_score": { "filter": { "term": { "genre.keyword": "Comedy" } } } } } // 查询包含多个值的记录 POST /movies/_search { "query": { "constant_score": { "filter": { "terms": { "genre.keyword": [ "Comedy", "Romance" ] } } } } }
这里如果我们想做精确匹配,我们可以增加一个count字段并使用bool查询来解决。
Step1.从业务角度,按需改进ES的数据模型
POST /movies_new/_bulk { "index":{"_id":1}} { "title": "Father of the Bridge Part II", "year": 1995, "genre": "Comedy", "genre_count":1 } { "index":{"_id":2}} { "title": "Dave", "year": 1993, "genre": ["Comedy", "Romance"], "genre_count":2 }
这里可以看到,我们给genre字段新增一个匹配的genre_count字段,代表genre字段有几个值。
Step2.使用bool查询进行精确匹配
// 方式一:使用must,有算分 POST /movies_new/_search { "query": { "bool": { "must": [ {"term":{"genre.keyword": {"value":"Comedy"}}}, {"term":{"genre_count": {"value":1}}} ] } } } // 方式二:使用filter,无算分 POST /movies_new/_search { "query": { "bool": { "filter": [ {"term":{"genre.keyword": {"value":"Comedy"}}}, {"term":{"genre_count": {"value":1}}} ] } } }
小结
本篇,我们了解了ElasticSearch中的结构化数据和结构化搜索的概念,并通过几个实例了解了如何对结构化数据进行搜索。在ES中,我们主要使用term对结构化数据进行搜索,而主要使用match对文本进行全文搜索。
参考资料
极客时间,阮一鸣,《ElasticSearch核心技术与实战》
作者:周旭龙
出处:https://edisonchou.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
标签:结构化,Elastic,之旅,term,genre,POST,Comedy,ES From: https://www.cnblogs.com/edisonchou/p/-/edc_elastic_study_notes_chap09