Elasticsearch中Text和Keyword类型的区别

很多刚开始学习 Elasticsearch 的人经常会混淆Text 和Keyword数据类型。 它们之间的区别很简单,但非常关键。

不同点

它们之间的本质区别在于:对于Text类型,将文本存储到倒排索引之前,会使用分析器对其进行分析,而Keyword类型则不会分析。文档是否被分析过会影响其查询的结果。关于倒排索引和分析器的内容可以参考:https://www.jianshu.com/p/04d29098851a

如何选择字段类型

如果将包含字符串的文档添加到 Elasticsearch,而之前没有定义字段的映射关系,那么 Elasticsearch 会自动创建一个包含TextKeyword类型的动态映射。 即使它适用于动态映射,也建议在文档添加之前定义索引的映射关系,以节省空间并提高写入速度。
如:未定义mapping,直接添加文档内容,发现"message”的数据类型是text,“message.keyword"的数据类型是keyword

PUT /demo/_doc/1
{
  "message":"this is a message"
}
#查看索引的mapping信息
GET /demo/_mapping

返回mapping的结果

{
  "demo" : {
    "mappings" : {
      "properties" : {
        "message" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

现在新建一个索引text-vs-keyword,并设置其mapping,keyword_field字段设置为keyword类型,text_field字段设置为text类型,text_and_keyword_mapping为多字段类型,其本身为text类型,而text_and_keyword_mapping.keyword字段为keyword类型。

#新建索引
PUT /text-vs-keyword
#设置索引mapping
PUT /text-vs-keyword/_mapping
{
    "properties": {
        "keyword_field": {
            "type": "keyword"
        },
        "text_field": {
            "type": "text"
        },
        "text_and_keyword_mapping": {
            "type": "text",
            "fields": {
                "keyword_type": {
                    "type": "keyword"
                }
            }
        }
    }
}

工作原理

这两种字段类型在倒排索引中的存储方式不同,索引过程中的差异会影响Elasticsearch 进行查询的时间。
首先添加一条文档

POST /text-vs-keyword/_doc/example
{
    "keyword_field": "The quick brown fox jumps over the lazy dog",
    "text_field": "The quick brown fox jumps over the lazy dog"
}

添加后,索引中便会有一条文档

{
    "_index": "text-vs-keyword",
    "_type": "_doc",
    "_id": "example",
    "_score": 1.0,
    "_source": {
        "keyword_field": "The quick brown fox jumps over the lazy dog",
        "text_field": "The quick brown fox jumps over the lazy dog"
    }
}

Keyword类型

对于keyword类型,由于Elasticsearch不会使用分析器对其进行分析,所以你输入什么文本,索引就会按照原样进行保存。下图为文本在倒排索引中存储的样子。

image.png

Text类型

对于text类型,Elasticsearch会先使用分析器对文本进行分析,再存储到倒排索引中。Elasticsearch默认使用标准分析器(standard analyzer),先对文本分词再转化为小写。关于标准分析器可以参考先前文章:https://www.jianshu.com/p/04d29098851a
标准分析器对文本进行分析后的结果

POST /text-vs-keyword/_analyze
{
  "analyzer": "standard",
  "text": "The quick brown fox jumps over the lazy dog"
}
#响应结果
{
  "tokens" : [
    {
      "token" : "the",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "quick",
      "start_offset" : 4,
      "end_offset" : 9,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "brown",
      "start_offset" : 10,
      "end_offset" : 15,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "fox",
      "start_offset" : 16,
      "end_offset" : 19,
      "type" : "<ALPHANUM>",
      "position" : 3
    },
    {
      "token" : "jumps",
      "start_offset" : 20,
      "end_offset" : 25,
      "type" : "<ALPHANUM>",
      "position" : 4
    },
    {
      "token" : "over",
      "start_offset" : 26,
      "end_offset" : 30,
      "type" : "<ALPHANUM>",
      "position" : 5
    },
    {
      "token" : "the",
      "start_offset" : 31,
      "end_offset" : 34,
      "type" : "<ALPHANUM>",
      "position" : 6
    },
    {
      "token" : "lazy",
      "start_offset" : 35,
      "end_offset" : 39,
      "type" : "<ALPHANUM>",
      "position" : 7
    },
    {
      "token" : "dog",
      "start_offset" : 40,
      "end_offset" : 43,
      "type" : "<ALPHANUM>",
      "position" : 8
    }
  ]
}

根据分析后的结果,下图为分词存储在倒排索引中的样子。


image.png

Text和Keyword的查询区别

现在已经知道了TextKeyword存储在倒排索引中的区别,接下来学习他们在查询中的区别。
查询分为两种查询

  • Match Query
  • Term Query

Match QueryTerm Query的区别与TextKeyword的区别类似,Match Query在查询时会对输入的关键词进行分析,而Term Query不会。
Elasticsearch 的查询原理是将查询的关键词与倒排索引中的词条进行匹配,查询的关键词与倒排索引中的词条必须完全相同视为匹配,否则不匹配。 这意味着在插入文档时是否进行分析和查询时是否进行分析将产生非常不同的结果。

不同的字段和不同的查询一共可以产生4种情况:以X代表不分析,O代表分析,左侧代表插入文档时是否分析,右侧代表查询时是否分析,则OX代表插入时分析,查询时不分析。

Term Query Match Query
keyword XX XO
text OX OO

使用Term Query查询keyword字段

由于插入文档的keyword字段和Term Query查询时都不会进行分析,因此只有当文本完全匹配才会返回结果。

GET /text-vs-keyword/_search
{
  "query": {
    "term": {
      "keyword_field": {
        "value": "The quick brown fox jumps over the lazy dog"
      }
    }
  }
}
#返回结果
"hits": [{
    "_index": "text-vs-keyword",
    "_type": "_doc",
    "_id": "example",
    "_score": 0.2876821,
    "_source": {
        "keyword_field": "The quick brown fox jumps over the lazy dog",
        "text_field": "The quick brown fox jumps over the lazy dog"
    }
}]

如果尝试文档中的一些词,由于不能与整篇文档相匹配,也不会返回结果。

GET /text-vs-keyword/_search
{
  "query": {
    "term": {
      "keyword_field": {
        "value": "The"
      }
    }
  }
}

使用Match Query查询keyword字段

GET /text-vs-keyword/_search
{
  "query": {
    "match": {
      "keyword_field": "The quick brown fox jumps over the lazy dog"
    }
  }
}
#返回结果
"hits": [{
    "_index": "text-vs-keyword",
    "_type": "_doc",
    "_id": "example",
    "_score": 0.2876821,
    "_source": {
        "keyword_field": "The quick brown fox jumps over the lazy dog",
        "text_field": "The quick brown fox jumps over the lazy dog"
    }
}]

这里有个疑问,查询关键词分析后的各个分词与倒排索引中的“The quick brown fox jumps over the lazy dog”不完全匹配,但为什么会产生结果呢?

这是因为我们在Match Query查询时使用的分析器不是标准分析器,Elasticsearch使用了关键词分析器(Keyword Analyzer),因此 Elasticsearch 在查询中没有任何改变。更多分析器可以参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-analyzers.html
查看Keyword Analyzer分析后的结果,发现并没有对搜索关键词进行分词。

GET /text-vs-keyword/_analyze
{
  "text": "The quick brown fox jumps over the lazy dog",
  "analyzer": "keyword"
}
#返回结果
{
    "token": "The quick brown fox jumps over the lazy dog",
    "start_offset": 0,
    "end_offset": 43,
    "type": "word",
    "position": 0
}

当选择标准分词器时进行Match Query查询时将不会得到任何结果。

GET /text-vs-keyword/_search
{
  "query": {
    "match": {
      "keyword_field": {
        "query": "The quick brown fox jumps over the lazy dog",
        "analyzer": "standard"
      }
    }
  }
}

使用Term Query查询text字段

text字段在文档插入时会对文本进行分析,得到若干个分词。
尝试两条查询语句,一条查询关键词为完整的句子,另一条只有一个单词。

GET /text-vs-keyword/_search
{
  "query": {
    "term": {
      "text_field": {
        "value": "The quick brown fox jumps over the lazy dog"
      }
    }
  }
}
GET /text-vs-keyword/_search
{
  "query": {
    "term": {
      "text_field": {
        "value": "The"
      }
    }
  }
}

两条语句都返回空结果:

  • 第一个查询没有产生任何结果,因为经过分析器分析后,在倒排索引中,从未存储整个句子,索引过程只存储分析后的分词。
  • 第二个查询也没有产生任何结果。 索引关键字为“The”,而标准分析器中的小写字母过滤器会将分词转化为小写,因此在倒排索引中,它存储的时“the”。

将查询单词转换为小写试下,由于查询关键字"the"与倒排索引中的"the"正好匹配,所以会返回该条记录。

GET /text-vs-keyword/_search
{
  "query": {
    "term": {
      "text_field": {
        "value": "the"
      }
    }
  }
}
#返回结果
"hits": [{
    "_index": "text-vs-keyword",
    "_type": "_doc",
    "_id": "example",
    "_score": 0.39556286,
    "_source": {
        "keyword_field": "The quick brown fox jumps over the lazy dog",
        "text_field": "The quick brown fox jumps over the lazy dog"
    }
}]

使用Match Query查询text字段

text字段和Match Query查询都会进行分析。
下面尝试两条查询语句

GET /text-vs-keyword/_search
{
  "query": {
    "match": {
      "text_field": "The"
    }
  }
}
GET /text-vs-keyword/_search
{
  "query": {
    "match": {
      "text_field": "the LAZ dog tripped over th QUICK brown dog"
    }
  }
}

这两条查询语句都返回了结果:

  • 第一个查询产生了一个结果,因为查询关键字中的“The”被分析为“the”,它与倒排索引中存储的完全匹配。
  • 第二个查询虽然并非所有分词都在倒排索引中,但仍会产生结果。因为只要查询的一个分词与倒排索引中的分词完全匹配,Elasticsearch 仍会返回这个结果。

如何选择这两个数据类型

以下情况推荐使用keyword类型:

  • 需要完全匹配的查询
  • 需要用于通配符查询
    以下情况推荐使用text类型:
  • 希望使用自动补全的功能
  • 希望使用搜索系统

结论

掌握textkeyword数据类型的工作原理是学习Elasticsearch的内容之一,这两者的区别似乎很简单,但非常重要。如果需要两种数据类型,则可以在创建映射时使用多字段功能。

参考

https://codecurated.com/blog/elasticsearch-text-vs-keyword/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容