ELK 学习笔记(三)—— 关于 Elasticsearch mapping


概要

前两天学习 Elasticsearch 的时候,我跳过了 mapping 部分,直接录入数据后查询,当时遗留了一些疑问,这篇文章正好学习这一部分

Mapping 是什么?

在创建索引后,可以手动创建索引的 mapping,也可以直接提交数据,Elasticsearch 会自动创建 mapping(dynamic mapping)

mapping 中定义了我们数据中各个字段的类型,以及这个字段如何分词等相关属性。

这里查看一下之前文章录入数据时 Elasticsearch 自动创建的 mapping

curl -X GET "localhost:9200/books_idx/_mapping?pretty"

返回数据

{
  "books_idx" : {
    "mappings" : {
      "properties" : {
        "author" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "isbn" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "pubdate" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          },
          "fielddata" : true
        },
        "publish" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          },
          "fielddata" : true
        }
      }
    }
  }
}

Ps:忽略 fielddata 字段,那是后来手动修改的属性

比如数据中的 author 字段,Elasticsearch把它设置为 text 类型,并且为它添加了属性,属性名称叫 keyword, 这个 keyword 属性类型是 keyword 类型,设置 ignore_above 属性值为 256,即如果数据内容长度超过这一设置,将不会被索引或存储

"author" : {
  "type" : "text",
  "fields" : {
    "keyword" : {
      "type" : "keyword",
      "ignore_above" : 256
  }
}

那么 textkeyword 有什么区别呢,Elasticsearch 会把 text 类型进行分词存储,便于全文检索等功能,而如果是 keyword 类型,那么这个字段不会被分词,搜索时用于精确搜索,可以用于排序和聚集

字段多类型

很多时候,我们的数据内容可能即需要精确的查找,又想让这个字段支持模糊搜索,那就需要设置这个字段为多个类型,Elasticsearch 在自动创建 mapping 的时候已经是这么做的了

使用方法就是,如果想要在这个字段上模糊搜索,就使用 author,如果想要精确查找某个作者,就使用 author.keyword

到这里,已经解决了上篇文章结尾遗留的问题,稍后就那个小的遗留问题进行补充

Elasticsearch 类型

现在再看一下 Elasticsearch 支持的基础类型

序号 类型 简要描述
1 text 自动分词,用于模糊搜索等功能
2 keyword 用于精确查找、排序、聚合操作等
3 date 录入指定格式的数据,能够进行排序转换等,详见:date
4 integer 32位整数,还有:long short byte double float 等,详见:number
6 boolean 可以在搜索时用于判断文档状态,或用于脚本,详见:boolean
7 ip 可以存储 IPv4 或者 IPv6 类型的地址,可用子网掩码进行搜索,详见:ip

除了基础类型,还有关于层级的类型说明,如:objectnested,还有关于位置的类型,就不多描述了,用到了参考文档

另外,Field 属性里的类型可以参考Field datatypes

遗留问题

上一篇《ELK学习笔记(二)——关于 Elasticsearch 检索》遗留的小问题,现在就很明确了,因为当时查询用 publish 出版社字段来进行聚合数量统计,但是这个字段是 text 类型的,导致查询出的结果GG(部分)

"years_count" : {
  "doc_count_error_upper_bound" : 0,
  "sum_other_doc_count" : 10,
  "buckets" : [
    {
      "key" : "出",
      "doc_count" : 6
    },
    {
      "key" : "版",
      "doc_count" : 6
    },
    {
      "key" : "社",
      "doc_count" : 5
    },
    {
      "key" : "业",
      "doc_count" : 3
    }
    ...
  }
}

现在看来很好解决,使用字段的属性 keyword 原始的字段进行聚合统计查询就可以了

curl -X GET "localhost:9200/books_idx/_doc/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "aggs": {
    "years_count": {
      "terms": { "field": "publish.keyword" }
    }
  }
}
'

结果如下(部分)

"aggregations" : {
  "years_count" : {
    "doc_count_error_upper_bound" : 0,
    "sum_other_doc_count" : 0,
    "buckets" : [
      {
        "key" : "电子工业出版社",
        "doc_count" : 2
      },
      {
        "key" : "人民邮电出版社",
        "doc_count" : 1
      },
      {
        "key" : "作家出版社",
        "doc_count" : 1
      },
      {
        "key" : "北京联合出版公司",
        "doc_count" : 1
      },
      {
        "key" : "机械工业出版社",
        "doc_count" : 1
      }
    ]
  }
}

手动创建 Mapping

只需要按照 JSON 规则,PUT 到相应名称的索引即可,前提是索引已经存在

curl -X PUT "localhost:9200/my_idx/_mapping?pretty" -H 'Content-Type: application/json' -d'
{
  "properties": {
    "name": {
      "type": "keyword"
    }
  }
}
'

更新 Mapping

已经创建的 Mapping 是不能修改字段的类型的,可以添加新的字段,也可以增加字段的类型,比如原先设置了 auther 字段为 text 类型,后来想要精确查找,重新PUT一份覆盖就可以了

删除 Mapping

It is no longer possible to delete the mapping for a type. Instead you should delete the index and recreate it with the new mappings.

官方文档说不再支持删除 mapping,当你想要删除的时候,正确的做法是直接删除索引并重新创建

Mapping 的学习就先到这里,后续用到其它的知识点再进行补充

参考

  1. Elasticsearch Reference [7.5] » Mapping