Elasticsearch已升级,新版Elasticsearch keyword博客参考下面这篇
【Elasticsearch教程8】Mapping字段类型之keyword
keyword类型通常存储结构性数据,而不是毫无规律可言的文本信息。
场景 | 值 |
---|---|
订单状态的枚举值 | 1:未付款;2:已付款;3:申请退款;4:已退款 |
HTTP状态码 | 200;400;500;404 |
手机号/邮箱/性别 | 对手机号没必要分词,也不需要数学计算,所以也不能设为数字类型 |
用户画像标签 | 学生,IT男,屌丝女,孕妈,社会中产 |
(1)创建一个文档
PUT /pigg_user/_doc/1
{
"name": "冬哥",
"age": 32
}
(2)查询数据
GET /pigg_user/_doc/1/_source
#返回结果如下,说明插入成功:
{
"name" : "冬哥",
"age" : 32
}
(3)查询name="冬哥"的数据
GET /pigg_user/_search
{
"query": {
"term": {
"name": "冬哥"
}
}
}
#返回结果如下,居然没有搜索到???
{
...省略其它信息...
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
(4)查看文档的mapping
要想探知没有搜到的原因,得先看排查文档的mapping。
发现name是text类型,其下面有一个keyword子类型。
GET /pigg_user/_mapping
#返回如下
{
"pigg_user" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : { #这行的keyword是字段名,全称是name.keyword
"type" : "keyword", #这行的keyword是指类型
"ignore_above" : 256 #这里的ignore_above下面会讲
}
}
}
}
}
}
}
(5)分析原因
如果不设置mapping,ES默认把字符串设为text类型,并包含一个keyword子类型。
name是text类型,“冬哥”这个词已经被拆成“冬”和“哥”这2个词项。
所以上面用term来匹配“冬哥”时,查询不到数据。
简单理解:
#根据name匹配“冬”,可以查询到文档
GET /pigg_user/_search
{
"query": {
"term": {
"name": "冬"
}
}
}
#根据name.keyword匹配"冬哥",可以查询到文档
GET /pigg_user/_search
{
"query": {
"term": {
"name.keyword": "冬哥"
}
}
}
#根据name.keyword匹配"冬",查询不到文档
GET /pigg_user/_search
{
"query": {
"term": {
"name.keyword": "冬"
}
}
}
#先删除之前创建的index
DELETE pigg_user
#设置name为keyword,age为short。
PUT pigg_user
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"age": {
"type": "short"
}
}
}
}
#新增一个文档
PUT /pigg_user/_doc/1
{
"name": "冬哥",
"age": 32
}
#根据name精确匹配,可以查到数据
GET /pigg_user/_search
{
"query": {
"term": {
"name": "冬哥"
}
}
}
首先随意往ES插一条数据:
put my_index/_doc/1
{
"name": "李星云"
}
查看ES自动生成的mapping,name是text类型,其下还有子类型keyword,且"ignore_above" : 256
GET /my_index/_mapping
name定义如下:
"properties" : {
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
对于keyword类型, 可设置ignore_above限定字符长度。超过 ignore_above 的字符会被存储,但不会被倒排索引。比如ignore_above=4,”abc“,”abcd“,”abcde“都能存进ES,但是不能根据”abcde“检索到数据。
【1】创建一个keyword类型的字段,ignore_above=4
PUT test_index
{
"mappings": {
"_doc": {
"properties": {
"message": {
"type": "keyword",
"ignore_above": 4
}
}
}
}
}
【2】向索引插入3条数据:
PUT /test_index/_doc/1
{
"message": "abc"
}
PUT /test_index/_doc/2
{
"message": "abcd"
}
PUT /test_index/_doc/3
{
"message": "abcde"
}
此时ES倒排索引是:
词项 | 文档ID |
---|---|
abc | 1 |
abcd | 2 |
【3】根据message进行terms聚合: |
GET /test_index/_search
{
"size": 0,
"aggs": {
"term_message": {
"terms": {
"field": "message",
"size": 10
}
}
}
}
返回结果:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"message" : "abcd"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"message" : "abc"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"message" : "abcde"
}
}
]
},
"aggregations" : {
"term_message" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [#注意这分组里没有”abcde“
{
"key" : "abc",
"doc_count" : 1
},
{
"key" : "abcd",
"doc_count" : 1
}
]
}
}
}
【4】根据”abcde“进行term精确查询,结果为空
GET /test_index/_search
{
"query": {
"term": {
"message": "abcde"
}
}
}
然后结果:
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
通过上面结果能知道”abcde“已经存入ES,也可以搜索出来,但是不存在词项”abcde“,不能根据”abcde“作为词项进行检索。
对于已存在的keyword字段,其ignore_above子属性可以修改,但只对新数据有效。