Press "Enter" to skip to content

【Elasticsearch教程18】Mapping字段类型之text 以及term、match和analyzer

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

 

Elasticsearch Mapping字段类型之text 以及term、match和analyzer

 

一、text场景

 

text
类型是适合全文搜索
的场景,ES会将文本分析成多个词并索引。

text
类型适合存放易阅读的
(human-readable)非结构化
文本,比如邮件内容、评论、商品介绍等
对于阅读性差的文本,如系统日志、Http请求体这些machine-generated数据,可以用wildcard
类型
text
类型不适合排序
聚合
(虽然可以实现,但是不建议)
如果要进行排序
聚合
,建议使用keyword
类型
所以可以给text
类型添加keyword子类型
token_count子类型
,各司其职

PUT pigg_test_text
{
 
  "mappings": {
 
    "properties": {
 
      "name": {
  # 姓名 name
        "type": "text",
        "fields": {
 
          "keyword": {
 # 子字段 name.keyword
            "type": "keyword",
            "ignore_above" : 256
          },
          "length": {
  # 子字段 name.length
            "type": "token_count",
            "analyzer": "standard"
          }
        }
      },
      "tag": {
 # 标签 tag
        "type": "keyword"
      },
      "word": {
 # 台词 word
        "type": "text"
      }
    }
  }
}

 

二、term
查询

term
判断某个字段是否包含
某个确定的值。一般用在keyword
integer
date
token_count
ip
等类型上
避免在text
类型上用term
,在text
上应该用match
match_phrase
来全文搜索

先插入两条《王者荣耀》里英雄的数据:

 

PUT pigg_test_text/_doc/1
{
 
  "name": "亚瑟王",
  "tag": ["对抗路", "打野"],
  "word": [
      "王者背负,王者审判,王者不可阻挡"
    ]
}
PUT pigg_test_text/_doc/2
{
 
  "name": "关羽",
  "tag": ["对抗路", "辅助"],
  "word": [
      "把眼光从二爷的绿帽子上移开",
      "聪明的人就应该与我的大刀保持安全距离"
    ]
}

 

(1)查询name
亚瑟王
的人

name.keyword
上用term
查询,返回id=1的文档
注意:term
不是等于的意思,是包含
的意思

GET pigg_test_text/_search
{
 
  "query": {
 
    "term": {
 
      "name.keyword": "亚瑟王"
    }
  }
}

 

(2)查询可走对抗路的人

tag
上用term
查询,返回id=1和2的文档,因为他们的tag
包含
对抗路

GET pigg_test_text/_search
{
 
  "query": {
 
    "term": {
 
      "tag": "对抗路" 
    }
  }
}

 

(3)查询是打野或辅助的人

tag
上用terms
查询(注意多了个s),返回id=1和2的文档
因为terms
查询只要包含
数组中任意一个就算匹配

GET pigg_test_text/_search
{
 
  "query": {
 
    "terms": {
 
      "tag": ["打野", "辅助"]
    }
  }
}

 

(4)查询name
是3个字的人

token_count
类型的name.length
上做精确匹配,返回亚瑟王
的文档

GET pigg_test_text/_search
{
 
  "query": {
 
    "term": {
 
      "name.length": 3
    }
  }
}

 

三、match
查询

 

虽然上面亚瑟王
关羽
这2个文档内容是中文,而且我也没有配置ik中文分词器
,但是这不影响我们的学习,我们只要知道中文被默认的standard analyzer
切分成独立的汉字就行了。

 

match
全文搜索鼓励王
,返回亚瑟王
文档,因为匹配中了
这个汉字。

 

GET pigg_test_text/_search
{
 
  "query": {
 
    "match": {
 
      "name": "鼓励王"
    }
  }  
}

 

对上面这条语句不是很理解的话,我从亚瑟王
如何存储?和鼓励王
如何搜索?这2个角度的问题来解释。

 

1.亚瑟王
如何存储?

 

_termvectors
term

 

查询id=1的文档的name字段的词条向量
GET pigg_test_text/_doc/1/_termvectors?fields=name

 

返回


这3个词,说明在倒排索引
里有类似如下的关系:

 

 

文档ID
1
1
1

 

2.鼓励王
如何搜索?

 

第1种方法:使用_analyze
分析standard
这个分析器是如何分割搜索关键字的。这里得指定name
字段上search-time
analyzer
,即search_analyzer

 

GET /_analyze
{
 
  "analyzer" : "standard",
  "text" : "鼓励王"
}
返回"鼓"、"励"、"王"这3个token

 

第2种方法:使用_validate
验证语句是否合法,其参数explain
(默认为true)会解释语句的执行计划

 

GET pigg_test_text/_validate/query?explain
{
 
  "query": {
 
    "match": {
 
      "name": "鼓励王"
    }
  }  
}

 

返回结果如下,name:鼓 name:励 name:王
说明是把鼓励王
拆成3个汉字分别到name
字段上做匹配的。

 

"valid" : true,
"explanations" : [
  {
 
    "index" : "pigg_test_text",
    "valid" : true,
    "explanation" : "name:鼓 name:励 name:王"
  }
]

 

第3种方法:使用_explain
查询鼓励王
是如何匹配到id=1的文档的?这种方式的前提是我们已经知道关键词匹配到哪个文档了,想知道匹配的原因。

 

解释`鼓励王`为何在name字段上匹配到id=1的文档
GET /pigg_test_text/_explain/1
{
 
  "query" : {
 
    "match" : {
  "name" : "鼓励王" }
  }
}

 

返回内容比较长,也比较复杂,因为涉及到打分机制,这里就贴一个重点:

 

"description" : "weight(name:王 in 0) [PerFieldSimilarity], result of:",

 

说明是
这个字让鼓励王
name
字段上匹配到id=1的文档的。

 

3. match的参数

 

match
还有2个比较重要的参:operator
minimum_should_match
,他们可以控制match
查询的行为。

 

3.1 operator

 

上面match
查询鼓励王
的语句,其实可以写成如下:

 

GET pigg_test_text/_search
{
 
  "query": {
 
    "match": {
 
        "message": {
 
          "query": "鼓励王",
          "operator": "or"
        }
    }
  }  
}

这个operater
的默认值就是or
,就是只要匹配到任意一个词,就算匹配成功。
如果要”鼓励王”这三个词全部匹配,可以设置"operator": "and"

GET pigg_test_text/_validate/query?explain=true
{
 
  "query": {
 
    "match": {
 
        "name": {
 
          "query": "鼓励王",
          "operator": "and"
        }
    }
  }  
}
返回如下:说明这3个字都得匹配
"explanations" : [
  {
 
    "index" : "pigg_test_text",
    "valid" : true,
    "explanation" : "+name:鼓 +name:励 +name:王"
  }
]

 

3.1 minimum_should_match

minimum_should_match
可以设置匹配的最小词数,不要与operator
一起使用,意思会冲突。
它可以赋值正数、负数、百分比等,但是我们常用的是设置一个正数,即指定最小匹配的词数。

指定要至少匹配成功2个字,才算文档匹配成功
GET pigg_test_text/_search
{
 
  "query": {
 
    "match": {
 
        "name": {
 
          "query": "鼓励王",
          "minimum_should_match": "2"
        }
    }
  }  
}

 

4. 匹配短语 match_phrase

 

match_phrase
短语查询,这个会将“绿帽子”
作为一个短语整体去匹配,而不会拆成3个字

 

该语句返回关羽这个文档,因为他的台词包含"绿帽子"
GET pigg_test_text/_search
{
 
  "query": {
 
    "match_phrase": {
 
      "word": "绿帽子"
    }
  }
}

 

查询语句的执行计划:

 

GET pigg_test_text/_validate/query?explain
{
 
  "query": {
 
    "match_phrase": {
 
      "word": "绿帽子"
    }
  }
}
返回如下:
"explanations" : [
  {
 
    "index" : "pigg_test_text",
    "valid" : true,
    "explanation" : "word:\"绿 帽 子\""
  }
]

 

四、分析器 analyzer

 

text
类型最重要的参数就是analyzer
(分析器),它决定在index-time
(创建或更新文档)和search-time
(搜索文档)如何对文本进行分词。

analyzer
:只配置了analyzer
时,在index-time
search-time
时,都使用analyzer
配置的分析器
search_analyzer
:配置了search_analyzer
时,在search-time
时,使用search_analyzer
配置的分析器

standard
分析器是text
类型的默认分析器,它按照词边界
对文本进行分割(如英语按照空格,中文切成独立汉字)。它删除了大多数标点符号和停止词并进行小写。standard
分析器对英语这样的西方语音是大多适用的。

分析器(analyzer)的配置
包含3个重要部分,依次是character filters
tokenizer
token filters

每当一个文档被 ingest 节点纳入,它需要经历如下的步骤,才能最终把文档写入到ES数据库中

 

 

英文中文analyzer配置项个数说明
character filters字符过滤器char_filter0~n个剥离html标签,转换特殊字符如&
and
tokenizer分词器tokenizer1个把文本按一定规则分割成一个个词token,比如常见的standard
whitespace
token filters词过滤器filter0~n个对上一步产生的token进行规范化。
比如转小写、删除或新增术语、同义词转换等。

 

举例:tokenizer
simple_pattern_split
,配置按照下划线_
来分割文本。

 

PUT my-index-000001
{
 
  "settings": {
 
    "analysis": {
 
      "analyzer": {
 
        "my_analyzer": {
 
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
 
        "my_tokenizer": {
 
          "type": "simple_pattern_split",
          "pattern": "_"
        }
      }
    }
  }
}
POST my-index-000001/_analyze
{
 
  "analyzer": "my_analyzer",
  "text": "亚瑟王__鼓励王_可丽王"
}

 

按照下划线_
切分后的词就是["亚瑟王", "鼓励王", "可丽王"]

其实我们工作中也不用配置很多,这里了解下就行,不用深究每一个选项
因为ES提供了很多开箱即用的内置analyzer
,我们可根据场景来选择
对于中文的分词,出名的有IK分词器
拼音分词器
,可以参考我之前写的ik中文分词器+pinyin拼音分词器+同义词

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。