为了能够将时间域视为时间,数字域视为数字,字符串域视为全文或精确值字符串,Elasticsearch需要知道每个域中数据的类型,这个信息包含在映射中。

如数据输入和输出中解释的,索引中每个文档都有类型。每种类型都有他自己的映射,或者模式定义。映射定义了类型中的域,每个域的数据类型,以及Elasticsearch如何处理这些域。映射也用于配置与类型有关的元数据。

我们会在类型和映射详细讨论映射。本节,我们只讨论足够让你入门的内容。

核心简单域类型

Elasticsearch支持如下简单域类型:

  1. 字符串:string
  2. 整数:byte,short,interger,long
  3. 浮点数:float,double
  4. 布尔型:boolean
  5. 日期:date

当你索引一个包含新域的文档——之前未曾出现——Elasticsearch会使用动态映射,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则:

JSON type 域 type
布尔型: true 或者 false boolean
整数: 123 long
浮点数: 123.45 double
字符串,有效日期: 2014-09-15 date
字符串: foo bar string

NOTE

这意味着如果你通过引号(”132”)索引一个数字,他会被映射为string类型,而不是long。但是,如果这个域已经映射为long,那么Elasticsearch会尝试将这个字符串转化为long,如果无法转化,则抛出一个异常。

查看映射

通过/_mapping,我们可以查看Elasticsearch在一个或多个索引中的一个或多个类型的映射。在开始章节,我们已经取得索引gb中类型tweet的映射:

  1. GET /gb/_mapping/tweet

Elasticsearch根据我们索引的文档,为域(称为 属性)动态生成的映射。

  1. {
  2. "gb": {
  3. "mappings": {
  4. "tweet": {
  5. "properties": {
  6. "date": {
  7. "type": "date",
  8. "format": "strict_date_optional_time||epoch_millis"
  9. },
  10. "name": {
  11. "type": "string"
  12. },
  13. "tweet": {
  14. "type": "string"
  15. },
  16. "user_id": {
  17. "type": "long"
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }

TIP

错误的映射,例如将age 域映射为string 类型,我不是interger,会导致查询出现令人困惑的结果。

检查一下!而不是假设你的映射是正确的。

自定义域映射

尽管在很多情况下基本域数据类型一斤够用,但你经常需要为单独域自定义映射,特别是字符串域。自定义映射允许你执行下面的操作:

  1. 全文字符串和精确值字符串域的区别
  2. 使用特定语言分析器
  3. 优化域以适应部分匹配
  4. 指定自定义数据格式
  5. 还有更多

域最重要的属性是type。对于不是string 的域,你一般只需要设置type:

  1. {
  2. "number_of_clicks": {
  3. "type": "integer"
  4. }
  5. }

默认,string 类型域会被认为包含全文。就是说,他们的值在索引前,会通过一个分析器,针对于这个域的查询在搜索前也会经过一个分析器。

string域映射的两个最重要属性是index 和 analyzer。

index

index属性控制怎样索引字符串。他可以是下面三个值:

analyzed

首先分析字符串,然后索引他。换句话说,以全文索引这个域。

not_analyzed

索引这个域,所以它能够被搜索,但索引的是精确值。不会对他进行分析。

no

不索引这个域。这个域不会被搜索到。

string 域 index属性默认是analyzed。如果我们想映射这个字段为一个精确值,我们需要设置他为 not_analyzed:

  1. {
  2. "tag": {
  3. "type": "string",
  4. "index": "not_analyzed"
  5. }
  6. }

NOTE

其他简单类型(例如 long,double,date等)也接受index 参数,但有意义的值只有no 和not_analyzed,因为他们永远不会被分析。

analyzer

对于analyzed字符串域,用analyzer 属性指定在搜索和索引时使用的分析器。默认,Elasticsearch使用standard 分析器,但你可以指定一个内置的分析器替代它,例如:whitespace、simple和english:

  1. {
  2. "tweet": {
  3. "type": "string",
  4. "analyzer": "english"
  5. }
  6. }

在自定义分析器,我们会展示怎样定义和使用自定义分析器。

更新映射

当你首次创建一个索引的时候,可以指定类型的映射。你也可以使用/_mapping 为新类型(或者为存在的类型更新映射)增加映射。

NOTE

尽管你可以增加一个存在的映射,你不能修改存在的域映射。如果一个域的映射已经存在,那么该域的数据可能已经被索引。如果你意图修改这个域的映射,索引的数据可能会出错,不能被正常的搜索。

我们可以更新一个映射来添加一个新域,但不能将一个存在的域从analyzed 改为not_analyzed。

为了描述指定映射的两种方式,我们先删除gb 索引:

  1. DELETE /gb

然后创建一个新索引,指定tweet域使用English 分析器:

  1. PUT /gb
  2. {
  3. "mappings": {
  4. "properties" : {
  5. "tweet" : {
  6. "type" : "text",
  7. "analyzer": "english"
  8. },
  9. "date" : {
  10. "type" : "date"
  11. },
  12. "name" : {
  13. "type" : "text"
  14. },
  15. "user_id" : {
  16. "type" : "long"
  17. }
  18. }
  19. }
  20. }

通过消息体中指定的mappings 创建了索引。

稍后,我们决定在tweet映射增加一个新的名为tag的not_analyzed的文本域,使用_mapping:

  1. PUT /gb/_mapping
  2. {
  3. "properties" : {
  4. "tag" : {
  5. "type" : "keyword"
  6. }
  7. }
  8. }

注意:我们不需要再次列出所有已存在的域,因为无论如何我们都无法改变他们。新域已经被合并到存在的映射中。

测试映射

你可以使用analyzer API测试字符串域的映射。比较下面两个请求的输出:

  1. GET /gb/_analyze
  2. {
  3. "field": "tweet",
  4. "text": "Black-cats"
  5. }
  6. //返回
  7. {
  8. "tokens" : [
  9. {
  10. "token" : "black",
  11. "start_offset" : 0,
  12. "end_offset" : 5,
  13. "type" : "<ALPHANUM>",
  14. "position" : 0
  15. },
  16. {
  17. "token" : "cat",
  18. "start_offset" : 6,
  19. "end_offset" : 10,
  20. "type" : "<ALPHANUM>",
  21. "position" : 1
  22. }
  23. ]
  24. }
  25. GET /gb/_analyze
  26. {
  27. "field": "tag",
  28. "text": "Black-cats"
  29. }
  30. //返回
  31. {
  32. "tokens" : [
  33. {
  34. "token" : "Black-cats",
  35. "start_offset" : 0,
  36. "end_offset" : 10,
  37. "type" : "word",
  38. "position" : 0
  39. }
  40. ]
  41. }

消息体里面传输我们想要分析的文本。

tweet 域产生两个词条black 和cat,tag域产生单独的词条Black-cats。换句话说,我们的映射正常工作。