Elasticsearch:Text vs. Keyword - 它们之间的差异以及它们的行为方式

这篇具有很好参考价值的文章主要介绍了Elasticsearch:Text vs. Keyword - 它们之间的差异以及它们的行为方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

很多刚开始学习 Elasticsearch 的人经常会混淆 text 和 keyword 字段数据类型。 它们之间的区别很简单,但非常关键。 在本文中,我将讨论两者之间的区别、如何使用它们、它们的行为方式以及使用哪一种。

区别

它们之间的关键区别在于,Elasticsearch 会在将 text 存储到倒排索引之前对其进行分析,而不会分析 keyword 类型。 分析或不分析将影响它在被查询时的行为方式。有关文本分析的内容,请阅读 “Elasticsearch: analyzer”。

keyword_type,Elasticsearch,Elastic,elasticsearch,大数据,全文检索,学习

如果你刚开始学习 Elasticsearch,还不知道什么是 Inverted Index 和 Analyzer,我建议你先阅读文章 “Elasticsearch:inverted index,doc_values 及 source”。

如何使用它们

如果你将包含字符串的文档索引到 Elasticsearch 之前没有定义到字段的映射,Elasticsearch 将创建一个包含 text 和 keyword 数据类型的动态映射。 但即使它适用于动态映射,我建议你在索引任何文档之前根据用例定义映射设置,以节省空间并提高写入速度。

这些是 text 和 keyword 类型的映射设置示例,请注意,我将使用我之前为该示例创建的名为 text-vs-keyword 的索引。

keyword mapping

# Create index
PUT text-vs-keyword

# Create keyword mapping
PUT text-vs-keyword/_mapping
{
  "properties": {
    "keyword_field": {
      "type": "keyword"
    }
  }
}

text mapping

# Create text mapping
PUT text-vs-keyword/_mapping
{
  "properties": {
    "text_field": {
      "type": "text"
    }
  }
}

Multi Fields

PUT text-vs-keyword/_mapping
{
  "properties": {
    "text_and_keyword_mapping": {
      "type": "text",
      "fields": {
        "keyword_type": {
          "type":"keyword"
        }
      }
    }
  }
}

 运行上面的三个命令之后,我们可以看到 text-vs-keyword 的 mapping 为:

GET text-vs-keyword/_mapping

上述命令的返回值为:

{
  "text-vs-keyword": {
    "mappings": {
      "properties": {
        "keyword_field": {
          "type": "keyword"
        },
        "text_and_keyword_mapping": {
          "type": "text",
          "fields": {
            "keyword_type": {
              "type": "keyword"
            }
          }
        },
        "text_field": {
          "type": "text"
        }
      }
    }
  }
}

上面显示了三个字段,它们有不同的字段类型定义。特别值得指出的是:上面的 keyword_field 及 keyword_type 这些名称都是开发者可以自己定义的名称,但是在很多的情况下,我们把他们的名字都取为 keyword,如下:

{
  "text-vs-keyword": {
    "mappings": {
      "properties": {
        "keyword": {
          "type": "keyword"
        },
        "text_and_keyword_mapping": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "text_field": {
          "type": "text"
        }
      }
    }
  }
}

他们是如何工作的

这两种字段类型在倒排索引中的索引方式不同。 索引过程的差异会影响你何时对 Elasticsearch 进行查询。

让我们索引一个文档,例如:

POST text-vs-keyword/_doc
{
  "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
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "text-vs-keyword",
        "_id": "fS95JoYBS2OSAePn1Qxh",
        "_score": 1,
        "_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 不会分析 Keyword 数据类型,这意味着你索引的 String 将保持原样。

那么,对于上面的例子,倒排索引中的字符串会是什么样子呢?

Term count
The quick brown fox jumps over the lazy dog
1

是的,你没看错,就是你写的那样。

Text

与 keyword 字段数据类型不同,索引到 Elasticsearch 的字符串在存储到倒排索引之前会经过分词器过程。 默认情况下,Elasticsearch 的标准分词器将拆分并小写化我们索引的字符串。 你可以在 Elasticsearch 的文档中了解有关标准分析器的更多信息。

keyword_type,Elasticsearch,Elastic,elasticsearch,大数据,全文检索,学习

Elasticsearch 有一个 API 可以检查文本在分析过程后的样子,我们可以尝试一下:

GET _analyze
{
  "text": "The quick brown fox jumps over the lazy dog",
  "analyzer": "standard"
}

我们可以看到如下的返回结果:

{
  "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
    }
  ]
}

所以根据上面的回复,这就是 text_field 字段的倒排索引的样子:

Term Count
the 1
quick 1
brown 1
fox 1
jumps 1
over 1
the 1
lazy 1
dog 1

与 keyword 略有不同,对吧? 但是你需要注意它在倒排索引中存储的内容,因为它会主要影响查询过程。

文本和关键字查询

现在我们了解了 text 和 keyword 在索引时的行为方式,让我们了解它们在被查询时的行为方式。

首先,我们必须知道字符串的查询有两种类型:

  • Match query
  • Term query

Match Query 和 Term Query 和 text 和 keyword 一样,区别在于 Match Query 中的 query 会先解析为 terms,而 Term Query 中的 query 不会。Term query 不分析搜索词。 Term query 仅搜索你提供的确切术语。 这意味着在搜索 text 字段时,术语查询可能返回较差的结果或没有返回结果。

查询 Elasticsearch 的工作原理是将查询的词与倒排索引中的词进行匹配,查询的词和倒排索引中的词必须完全相同,否则匹配不上。 这意味着在索引和查询结果中分析过的字符串和未分析过的字符串会产生截然不同的结果。

使用 Term Query 查询 keyword 字段

因为字段数据类型和查询都没有被分析,所以它们都需要完全相同才能产生结果。

如果我们尝试使用完全相同的查询:

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

上述命令返回的结果为:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "text-vs-keyword",
        "_id": "fS95JoYBS2OSAePn1Qxh",
        "_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 字段

让我们首先尝试使用 Match Query 对 keyword_field 查询相同的字符串 “The quick brown fox jumps over the lazy dog”,看看会发生什么:

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

结果应该是:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "text-vs-keyword",
        "_id": "fS95JoYBS2OSAePn1Qxh",
        "_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” 需要进行分词。如果按照使用 standard 分词器对它进行分析,它产生的术语与倒排索引中的 “The quick brown fox jumps over the lazy dog” (这是一整个术语)不完全匹配,但为什么它会产生结果呢?

没错,查询被分析是因为我们使用的是 Match Query,但 Elasticsearch 使用的不是 standard 分析器,而是 index-time 分析器,它被映射到 keyword 字段数据类型。 由于与 keyword 字段数据类型映射的分词器是 keyword Analyzer,因此 Elasticsearch 在查询中没有任何改变。我们尝试使用 term analyzer 来试试:

GET _analyze
{
  "analyzer": "keyword",
  "text": "The quick brown fox jumps over the lazy dog"
}

上述命令将生成:

{
  "tokens": [
    {
      "token": "The quick brown fox jumps over the lazy dog",
      "start_offset": 0,
      "end_offset": 43,
      "type": "word",
      "position": 0
    }
  ]
}

可以见得,它就是只有一个 term。

现在,让我们尝试使用 standard 分析器:

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

在上面,我们定义了 analyzer。这个实际上是 search_analyer。请详细阅读 “Elasticsearch: analyzer”。上述命令将不会返回任何的结果。其原因显而易见,查询字符串的倒排术语和 keyword_field 字段里的术语完全不同。

使用 Term Query 查询 text 类型

正如我们在上一节中看到的那样,text 类型的索引文档将包含许多术语。 为了显示查询如何与倒排索引中的术语匹配,让我们尝试两个查询,第一个查询将整个句子发送到 Elasticsearch:

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

由于使用 Term query 时,它不会对搜索的字符串 “The quick brown fox jumps over the lazy dog” 进行任何的分词,而 text_field 的倒排索引中没有这么长的完整术语。所以上述的查询不会有任何的结果。

 我们再进行如下的查询:

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

这两个查询都没有结果。

第一个查询没有产生结果,因为在倒排索引中,我们从未存储过整个句子,索引过程只存储已经从文本中分块的术语。

第二个查询也没有产生任何结果。 索引文档中有一个“The”,但记住分析器将单词小写,所以在 Inverted Index 中,它存储为 the

让我们用 the 再次尝试 Term 查询:

GET text-vs-keyword/_search
{
  "query": {
    "term": {
      "text_field": "the"
    }
  }
}

是的! 它产生了一个结果,因为查询的 the 与倒排索引中的 the 完全匹配。

使用 Match query 查询 text 类型

现在是使用 Match Query 进行 text 类型处理的时候了,因为它会分析这两种类型,所以很容易让它们产生结果。 让我们先尝试两个查询:

  • 第一个查询会将 The 发送到 Elasticsearch,我们知道使用 term query 不会产生任何结果,但是 match query 呢?
  • 第二个查询将发送 the LAZ dog tripped over the QUICK brown dog,有些词在倒排索引中,有些不在,Elasticsearch 会从中产生任何结果吗?
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"
    }
  }
}

是的! 两者都产生了结果:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.8339733,
    "hits": [
      {
        "_index": "text-vs-keyword",
        "_id": "fS95JoYBS2OSAePn1Qxh",
        "_score": 1.8339733,
        "_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。

第二个查询,虽然并非所有术语都在倒排索引中,但仍会产生一个结果。 Elasticsearch 将返回一个结果,即使只有一个查询的术语与倒排索引中的术语完全匹配。

如果你注意结果,有一个 _score 字段。 有多少查询词与倒排索引中的词完全匹配是影响分数的因素之一。请阅读我的另外文章 “Elasticsearch:分布式计分”。

该选 text 还是 keyword 呢?

在以下情况下使用 keyword 字段数据类型:

  • 你想要一个完全匹配查询
  • 你想让 Elasticsearch 像其他数据库一样运行
  • 你想用它来进行通配符查询

在以下情况下使用 text 字段数据类型:

  • 你想创建一个自动完成
  • 你想创建一个搜索系统

结论

了解 text 和 keyword 字段数据类型的工作原理是你想要在 Elasticsearch 中学习的内容之一,区别看似简单但很重要。

你需要了解并选择适合您的用例的字段数据类型,如果你需要两种字段数据类型,则可以在创建映射时使用 multi fields 功能。比如在我们上面已经创建的 text_and_keyword_mapping 字段。

最后,希望本文能帮助大家学习 Elasticsearch,了解 Elasticsearch 中 text 和 keyword 字段数据类型的区别。 谢谢阅读!文章来源地址https://www.toymoban.com/news/detail-780431.html

到了这里,关于Elasticsearch:Text vs. Keyword - 它们之间的差异以及它们的行为方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MyBatis中获取参数值的两种方式:${} 和 #{},以及它们之间区别是什么?

    ${}:的本质就是字符串拼接 #{}:的本质就是占位符赋值 ① 使用${}占位符,在字符串拼接的方式拼接sql,若为字符串类型或为日期类型的字段进行赋值时,需要手动加单引号 ② 使用#{}占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,自动添加单引

    2024年02月04日
    浏览(45)
  • 【概率论】事件的独立与事件的互斥(或互不相容)、以及它们之间的关系

        通俗的讲,两个事件的独立就是这两个事件发生与否互相不影响,比如:投掷骰子两次,第一次的结果与第二次的结果互不影响,把这两次投骰子看作两次事件,那么也就是说这两次事件独立。     事件 A 与事件 B 独立用概率来定义:P(AB) = P(A) P(B) 。因为

    2024年02月12日
    浏览(39)
  • es中的match、term、text、keyword、bool

    总结一下es中的match、term、text、keyword、bool等。比如我想搜索一辆“红色奥迪车”: match:在匹配时会对所查找的进行分词,然后按分词匹配查找,用于模糊查询。结果会将包含“红色”或“奥迪”的车都找出来。 term:对进行查找,用于精确查找。只有名

    2024年02月11日
    浏览(41)
  • es7.x Es常用核心知识快捷版1(分词和text和keyword)

    1.1.1 查看分词 standard标准分析器是将每个字都分出来; 而 ik_max_word是 最细粒度的分词, 将所有可能的词都分出来; ik_smart 是最粗粒度的分词 ; ik_smart 优点:特征是粗略快速的将文字进行分词,占用空间小,查询速度快 缺点:分词的颗粒度大,可能跳过一些重要分词,导致查询结果

    2024年02月09日
    浏览(45)
  • Elasticsearch中object类型与nested类型以及数组之间的区别

    0、一般情况下用object 类型来查es中为json对象的字段数据,用nested来查es中为JsonArray数组类型的字段数据。 1、默认情况下ES会把JSON对象直接映射为object类型,只有手动设置才会映射为nested类型 2、object类型可以直接使用普通的逗号(.)查询,比如 3、nested类型的查询需要使用

    2024年01月22日
    浏览(84)
  • css中预编译理解,它们之间区别

    css预编译器用一种专门的编程语言,它可以对web页面样式然后再编译成正常css文件,可以更加方便和高效的编写css代表。主要作用就是为css提供了变量,函数,嵌套,继承,混合等功能,以及更加易于维护和组织代码的结构。 常见的css预编译语言有:sass,less和stylus等等 区别

    2024年02月15日
    浏览(53)
  • Buildroot,Ubuntu,Debian,Yocto 它们分别是什么,它们之间的具体关系是什么

    1. Buildroot 定义: Buildroot是一个简化和加速嵌入式Linux系统开发过程的工具,提供一种容易、高效的方式来生成交叉编译工具链、根文件系统、内核映像和引导加载程序。Buildroot使用makefile和kconfig(和Linux内核使用的相同系统)来配置和构建整个嵌入式系统。 适用场景: 对于

    2024年04月25日
    浏览(36)
  • NLP和LLMs: 理解它们之间的区别

    NLP(自然语言处理)和LLMs(大型语言模型)都与处理自然语言相关,但它们的重点和范围略有不同。 自然语言处理(NLP): 定义 : 自然语言处理(NLP)是人工智能领域的一个子领域,专注于研究和开发使计算机能够理解、处理、生成自然语言文本的技术和方法。 目标 :

    2024年04月17日
    浏览(42)
  • Elasticsearch keyword 中的 ignore_above配置项

    关于es mapping的keyword ignore_above配置项的解释如下: Do not index any string longer than this value. Defaults to  2147483647  so that all values would be accepted. 不会索引大于ignore_above配置值的数据,默认值 2147483647字符。注意:动态mappings中自动为256。 Strings longer than the  ignore_above  setting will not

    2024年02月07日
    浏览(40)
  • 什么是Docker的容器编排工具,它们之间有何不同?

    随着Docker容器技术的广泛应用,容器编排工具成为了自动化部署、扩展和管理容器化应用程序的关键组件。这些工具提供了一种抽象层,帮助开发者和管理员更高效地管理大量的Docker容器,确保它们在不同的主机和环境中能够可靠地运行。目前,市场上流行的Docker容器编排工

    2024年02月19日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包