01
Term-level queries 简介
Term-level queries 术语级查询就是根据结构化数据中的精确值查找文档。
与( Full text queries)全文查询的不同之处在于,术语级查询不会分析检索词,而是匹配存储在字段中的确切术语。不知道这是什么意思?没关系,下面TeHero结合实例进行讲解。
Term-level queries系列脑图
ps:上图的xmind文件获取方式见文末!
通过上图可以看到,Term-level queries 一共有11种查询类型,标红的四种查询是我们常用的查询:term query、terms query、range query、wildcard query。 本文将先介绍:term query、terms query这两种查询!Let's Go!
以博客的数据为例,数据结构如下:
创建 blogs_index 和 tags_index(就是tag的详情):
PUT /blogs_index
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 1
}
},
"mappings": {
"_doc": {
"dynamic": false,
"properties": {
"id": {
"type": "integer"
},
"author": {
"type": "keyword"
},
"title": {
"type": "text",
"analyzer": "ik_smart"
},
"tag":{
"type": "integer"
},
"influence": {
"type": "integer_range"
},
"createAt": {
"type": "date"
}
}
}
}
}
PUT /tags_index
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 1
}
},
"mappings": {
"_doc": {
"dynamic": false,
"properties": {
"id": {
"type": "integer"
},
"tag_name": {
"type": "keyword"
}
}
}
}
}
批量导入数据:
POST _bulk
{"index":{"_index":"blogs_index","_type":"_doc","_id":"1"}}
{"id":1,"author":"方才兄","title":"关注我,系统学编程"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"2"}}
{"id":2,"author":"方才","title":"系统学编程,关注我"}
核心点:检索词不会被分词,作为一个Token/term
语句1:检索文档1的title字段的完整内容,发现居然检索不到文档!
POST /blogs_index/_doc/_search
{
"query": {
"term" : { "title" : "关注我,系统学编程" }
}
}
语句2:只检索关键词“编程”,可以检索文档1和文档2
POST /blogs_index/_doc/_search
{
"query": {
"term" : { "title" : "编程" }
}
}
在【ElasticSearch系列05:倒排序索引与分词Analysis】我们已经知道了es的检索过程【ps:该过程非常重要,一定要掌握,明白了这个检索过程,对于理解DSL语句非常有用】:
ps:如何知道es中文档的PostingList呢?直接使用_anlyze接口分析即可:
GET blogs_index/_analyze
{
"text": [ "关注我,系统学编程"],
"field": "title"
}
得到针对字段title,建立的PostingList:
{
"tokens": [
{
"token": "关注",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "我",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 1
},
{
"token": "系统学",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 2
},
{
"token": "编程",
"start_offset": 7,
"end_offset": 9,
"type": "CN_WORD",
"position": 3
}
]
}
1、检索会被分词的字段,match语句与term语句区别较大。
match 语句1:检索文档1的title字段的完整内容,得到文档1和文档2;
POST /blogs_index/_doc/_search
{
"query": {
"match" : { "title" : "关注我,系统学编程" }
}
}
简单分析下:
2、检索不会分词的字段:mathc语句与term语句效果一致
POST /blogs_index/_doc/_search
{
"query": {
"term" : { "author" : "方才兄" }
}
}
POST /blogs_index/_doc/_search
{
"query": {
"match" : { "author" : "方才兄" }
}
}
注意:match语句会对检索词分词,使用的分词器默认与被检索字段一致【对于author这个字段,type为keyword,所以哪怕使用的是match查询,检索词依然不会被分词】。上述两个语句都只能检索到文档1!
一般用于检索不会被分词的字段,主要是类型为:integer、keyword、boolean 的字段。
比如说我们这个blogs_index中的author字段,假如我们只想看作者为“方才兄”的blog,DSL语句如下:
POST /blogs_index/_doc/_search
{
"query": {
"term" : { "author" : "方才兄" }
}
}
比如,我想检索作者是【方才兄】和【方才】的文章:
POST /blogs_index/_doc/_search
{
"query": {
"terms" : { "author" : ["方才兄","方才"]}
}
}
该语句等价于sql语句【where author in (“"方才兄","方才")】
比如:有如下数据:
POST _bulk
{"index":{"_index":"blogs_index","_type":"_doc","_id":"3"}}
{"id":3,"author":"方才兄","title":"关注我,系统学编程","tag":[1,2,3]}
{"index":{"_index":"tags_index","_type":"_doc","_id":"1"}}
{"id":1,"tag_name":"这是标签1"}
{"index":{"_index":"tags_index","_type":"_doc","_id":"2"}}
{"id":2,"tag_name":"这是标签2"}
{"index":{"_index":"tags_index","_type":"_doc","_id":"3"}}
{"id":3,"tag_name":"这是标签3"}}
对于blogs_index中文档3,我们获取到了tag的idList集合,我们需要把tag的详细情况查出来:
GET /tags_index/_search
{
"query": {
"terms": {
"id": {
"index": "blogs_index",
"type": "_doc",
"id": "3",
"path": "tag"
}
}
}
}
参数解释:
index:从中获取术语值的索引。
type:从中获取术语值的类型。
id:用于获取术语值的文档的ID,是源字段_id,而不是我们自定义的字段id。
path:指定为获取terms过滤器实际值的路径的字段 。
使用场景:当需要terms语句包含大量术语时,从索引中的文档中获取这些术语值将是有益的。其实这种垮索引的查询方法,在实际中很难应用到,对数据结构有强制的要求,而且针对另一个index的查询条件,只能是 _id = xx,不能像sql一样随意书写where条件。
上述DSL语句等价于将sql语句【select * from tags_index where id in (1,2,3)】转化为了sql【select * from tags_index where id in (select tag from blogs_index where _id = 3)】。
下期预告:Term-level queries剩下的9种查询【关注公众号:方才编程,系统学习ES】