它们之间的差异以及行为方式
许多刚开始学习Elasticsearch的人经常将Text和Keyword字段数据类型混淆。它们之间的区别很简单,但非常关键。在本文中,我将讨论它们之间的区别,如何使用它们,如何表现以及在两者之间使用哪个。
差异
它们之间的关键区别在于,Elasticsearch将在将文本存储到反向索引之前对其进行分析,而不会分析关键字类型。已分析或未分析将影响查询时的行为。
如果您刚刚开始学习Elasticsearch,但仍然不了解什么是反向索引和分析器,建议您先阅读有关Elasticsearch的基本指南。
如何使用它们
如果您将包含字符串的文档索引到Elasticsearch,但之前未定义到字段的映射,则Elasticsearch将创建具有Text和Keyword数据类型的动态映射。但是,即使它可用于动态映射,我还是建议您根据用例为任何文档建立索引之前定义映射设置,以节省空间并提高写入速度。
这些是“文本”和“关键字”类型的映射设置的示例,请注意,我将使用在此示例之前创建的名为“ text-vs-keyword”的索引。
关键字对应
curl --request PUT \
--url http://localhost:9200/text-vs-keyword/_mapping \
--header 'content-type: application/json' \
--data '{ "properties": { "keyword_field": { "type": "keyword" } }}'
文字对应
curl --request PUT \
--url http://localhost:9200/text-vs-keyword/_mapping \
--header 'content-type: application/json' \
--data '{ "properties": { "text_field": { "type": "text" } }}'
多领域
curl --request PUT \
--url http://localhost:9200/text-vs-keyword/_mapping \
--header 'content-type: application/json' \
--data '{ "properties": { "text_and_keyword_mapping": { "type": "text", "fields": { "keyword_type": { "type":"keyword" } } } }}'
他们如何工作
两种字段类型在反向索引中的索引均不同。索引过程的差异会影响您对Elasticsearch进行查询的时间。
让我们为文档建立索引,例如:
curl --request POST \
--url http://localhost:9200/text-vs-keyword/_doc/example \
--header 'content-type: application/json' \
--data '{ "keyword_field":"The quick brown fox jumps over the lazy dog", "text_field":"The quick brown fox jumps over the lazy dog"}'
执行完上面的curl命令后,如果您在索引中获得了所有文档,则应该具有:
[ { "_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
让我们从简单的关键字开始。Elasticsearch不会分析关键字数据类型,这意味着您索引的字符串将保持不变。
因此,在上面的示例中,该字符串在反向索引中将是什么样?
是的,您是对的,与您所写的完全一样。
文本 Text
与关键字字段数据类型不同,索引为Elasticsearch的字符串在存储到反向索引中之前将经过分析器过程。默认情况下,Elasticsearch的标准分析器将拆分并降低我们索引的字符串。您可以在Elasticsearch的文档中了解有关标准分析仪的更多信息。
Elasticsearch有一个API,可以在分析过程后检查文本的外观,我们可以尝试以下方法:
curl --request POST \
--url http://localhost:9200/text-vs-keyword/_analyze?pretty \
--header 'content-type: application/json' \
--data '{ "analyzer": "standard", "text": "The quick brown fox jumps over the lazy dog"}'
因此,根据上面的响应,这就是text_field字段的倒排索引的样子
与关键字one仅有一点不同,对吧?但是您需要注意它存储在反向索引中的内容,因为它会严重影响查询过程。
查询文字和关键字
现在,我们了解了文本和关键字在建立索引后的行为,让我们了解它们在被查询时的行为。
首先,我们必须知道该字符串有两种查询类型:
- 匹配查询
- 字词查询
与“文字和关键字”相同,“匹配查询”和“术语查询”之间的区别在于,“匹配查询”中的查询将首先被分析成术语,而“术语查询”中的查询则不会。
查询Elasticsearch的方法是将查询的词与反向索引中的词进行匹配,查询的词与反向索引中的词必须完全相同,否则将无法匹配。这意味着索引和查询结果中的分析字符串和非分析字符串将产生非常不同的结果。
使用术语查询查询关键字字段
由于未同时分析字段数据类型和查询,因此它们都必须完全相同,以便产生结果。
如果我们尝试使用完全相同的查询:
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?size=0' \
--header 'content-type: application/json' \
--data '{ "query": { "term": { "keyword_field": "The quick brown fox jumps over the lazy dog" } }}'
Elasticsearch将返回结果:
{ "_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" } }}
如果我们尝试使用不完全正确的方法,即使倒排索引中包含单词:
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?size=0' \
--header 'content-type: application/json' \
--data '{ "query": { "term": { "keyword_field": "The" } }}'
由于查询中的字词与反向索引中的任何字词都不匹配,因此未返回任何结果。
使用匹配查询查询关键字字段
让我们首先尝试使用匹配查询查询相同的字符串“The quick brown fox jumps over the lazy dog”,并查询是否发生了以下情况:
curl --request POST \
--url http://localhost:9200/text-vs-keyword/_doc/_search \
--header 'content-type: application/json' \
--data '{ "query": { "match": { "keyword_field": "The quick brown fox jumps over the lazy dog" } }}'
结果应为:
{ "_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,但是Elasticsearch代替了标准分析器,而是使用了索引时间分析器,该索引时间分析器已映射到关键字字段数据类型。由于映射到关键字字段数据类型的分析器是术语分析器,因此Elasticsearch在查询中未进行任何更改。
现在,让我们尝试使用标准分析仪:
curl --request POST \
--url http://localhost:9200/text-vs-keyword/_doc/_search \
--header 'content-type: application/json' \
--data '{ "query": { "match": { "keyword_field": { "query": "The quick brown fox jumps over the lazy dog", "analyzer":"standard" } } }}'
不会产生任何结果,因为它会按术语分析查询,并且与倒排索引中的术语完全不匹配。
使用术语查询查询文本类型
正如我们在上一节中看到的那样,文本类型的索引文档将有许多术语。为了显示查询如何与反向索引中的术语匹配,让我们尝试两个查询,第一个查询将整个句子发送到Elasticsearch;第二个查询将整个句子发送到Elasticsearch。
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?pretty=' \
--header 'content-type: application/json' \
--data '{ "query": { "term": { "text_field": "The quick brown fox jumps over the lazy dog" } }}'
第二个只有“ The”。
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?pretty=' \
--header 'content-type: application/json' \
--data '{ "query": { "term": { "text_field": "The" } }}'
这两个查询均未产生结果。
第一个查询没有结果,因为在倒排索引中,我们从不存储整个句子,索引过程仅存储从文本中分块出来的词。
第二个查询也没有结果。在索引文档中有一个“ The”,但请记住分析器将单词小写,因此在“ Inverted Index”中,它存储为“ the”。
让我们使用“ the”再次尝试术语查询:
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?pretty=' \
--header 'content-type: application/json' \
--data '{ "query": { "term": { "text_field": "the" } }}'
是的!之所以产生结果,是因为查询的“ the”与倒排索引中的“ the”完全匹配。
使用匹配查询查询文本类型
现在该使用匹配查询输入文本类型了,因为它可以分析两种类型,因此很容易使它们产生结果。让我们先尝试两个查询
第一个查询将向“ Elasticsearch”发送“ The”,我们知道使用术语查询不会产生结果,但是匹配查询呢?
第二个查询将发送“ he LAZ dog tripped over th QUICK brown dog”,某些单词在倒排索引中,有些不在,Elasticsearch会从中产生任何结果吗?
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?pretty=' \
--header 'content-type: application/json' \
--data '{ "query": { "match": { "text_field": "The" } }}'
curl --request POST \
--url 'http://localhost:9200/text-vs-keyword/_doc/_search?pretty=' \
--header 'content-type: application/json' \
--data '{ "query": { "match": { "text_field": "the LAZ dog tripped over th QUICK brown dog" } }}'
是的!他们两个都产生了结果
{ "_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" } }
第一个查询产生了一个结果,因为分析了查询中的“ The”并使其成为与倒排索引中的“ the”完全匹配的“ the”。
尽管不是所有术语都在倒排索引中,但第二个查询仍会产生结果。即使仅查询的一项与反向索引中的一项完全匹配,Elasticsearch也会返回结果。
如果您注意结果,则有一个_score字段。与倒排索引中的一个词完全匹配的查询词有多少是影响得分的因素之一,但让我们将计算下来的得分另存为另一天。
何时使用一个或另一个
在以下情况下,使用关键字字段数据类型:
- 需要完全匹配查询
- 想使Elasticsearch功能像其他数据库一样
- 想将其用于通配符查询
在以下情况下,请使用文本字段数据类型:
- 要创建自动完成
- 要创建一个搜索系统
结论
了解文本和关键字字段数据类型的工作方式是您要在Elasticsearch中学习的一件事,区别似乎很简单,但很重要。
您将要了解并选择适合您的用例的字段数据类型,如果您想同时使用两种字段数据类型,则可以在创建映射时使用“多字段”功能。
最后,我希望本文能帮助您学习Elasticsearch并了解Elasticsearch中文本字段和关键字字段数据类型之间的区别。谢谢阅读!
(本文由闻数起舞翻译自Nushaba Gadimli的文章《Elasticsearch: Text vs. Keyword》,转载请注明出处,原文链接:https://medium.com/better-programming/elasticsearch-text-vs-keyword-2ccb99ec72ae)