Elasticsearch实践(三):Mapping

版本:Elasticsearch 6.2.4。

Mapping类似于数据库中的表结构定义,主要作用如下:

  • 定义Index下字段名(Field Name)
  • 定义字段的类型,比如数值型,字符串型、布尔型等
  • 定义倒排索引的相关配置,比如是否索引、记录postion等

Mapping完整的内容可以分为四部分内容:

  • 字段类型(Field datatypes)
  • 元字段(Meta-Fields)
  • Mapping参数配置(Mapping parameters)
  • 动态Mapping(Dynamic Mapping)

自动Mapping

如果没有手动设置Mapping,Elasticsearch默认会自动解析出类型,且每个字段以第一次出现的为准。

下面我们先看一下Elasticsearch默认创建的Mapping是什么样的。

首先我们创建一个索引:

PUT /user/

查询索引信息:

GET /user

结果:

{
  "user": {
    "aliases": {},
    "mappings": {},
    "settings": {
      "index": {
        "creation_date": "1540044686190",
        "number_of_shards": "5",
        "number_of_replicas": "1",
        "uuid": "_K5b8w7jRiuthf7QeQZhdw",
        "version": {
          "created": "5060299"
        },
        "provided_name": "user"
      }
    }
  }
}

增加一条数据:

PUT /user/doc/1
{
  "name":"Allen Yer",
  "job":"php",
  "age":22
}

PUT /user/doc/2
{
  "name":"Allen Yer",
  "job":0,
  "age":22
}

查询数据是否新增成功:

GET /user/doc/_count

结果:

{
  "count": 2,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  }
}

count为2,说明新增成功。然后我们查询下 mapping :

{
  "user": {
    "mappings": {
      "doc": {
        "properties": {
          "age": {
            "type": "long"
          },
          "job": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

发现自动为每个字段设置了类型:

  • name: text类型,另外额外增加了name.keyword字段,keyword类型;
  • job:text类型,另外额外增加了job.keyword字段,keyword类型;虽然第二次数据新增是数字类型,但还是以第一次为主;
  • age:long类型。

大家可以把索引删掉,将新增数据调整为先新增第2条,再新增第一条,发现报错了:

DELETE /user

PUT /user/doc/2
{
  "name":"Allen Yer",
  "job":0,
  "age":22
}

PUT /user/doc/1
{
  "name":"Allen Yer",
  "job":"php",
  "age":22
}

报错:

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "failed to parse [job]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "failed to parse [job]",
    "caused_by": {
      "type": "number_format_exception",
      "reason": "For input string: \"php\""
    }
  },
  "status": 400
}

也能说明以第一次为主以字段第一次的值类型为准。这也说明了默认创建mapping可能不是我们想要的,这就需要手动创建mapping,好处有:

  • 提前指定字段(通过设置甚至可以达到禁止自动增加字段的效果)
  • 合理设置字段类型,防止分词过多或者解析不合理。分词过大会导致磁盘空间占用大。

手动创建mapping

这次我们删掉mapping,并手动创建一个:

DELETE /user

PUT /user/
{
    "mappings": {
      "doc": {
        "properties": {
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "age": {
            "type": "long",
            "index": false
          },
          "job": {
            "type": "keyword"
          },
          "intro":{
            "type":"text"
          },
          "create_time": {
            "type": "date", 
            "format": "epoch_second"
        }
        }
     }
  }
}

字段类型说明:

  • name:text类型,会进行分词,支持模糊检索。
  • name.keyword : 这相当于是嵌套了一个字段,keyword类型,只能精确匹配,不支持分词。超过256字符长度不索引,也就没法搜索到。
  • age:long类型,支持精确匹配。
  • job:keyword类型,只能精确匹配,不支持分词。
  • intro:text类型,会进行分词,支持模糊检索。
  • create_time:date类型,支持10位时间戳。
注意:mapping生成后是不允许修改(包括删除)的。所以需要提前合理的的定义mapping。

元字段

_all

该字段用于在没有指定具体字段的情况下进行模糊搜索,可以搜索全部字段的内容。

原理是将所有字段的内容视为字符串,拼在一起放在一个_all字段上,但这个字段默认是不被存储的,可以被搜索。在query_string与 simple_query_string查询(Kibana搜索框用的这种查询方式)默认也是查询_all字段。

6.x 版本被默认关闭。

相关设置:

PUT my_index
{
  "mappings": {
    "my_type": {
      "_all": {
        "enabled": true,
        "store": false
      },
      "properties": {}
    }
  },
  "settings": {
    "index.query.default_field": "_all" 
  }
}

上述配置在5.x版本是默认配置:

  • 默认开启 _all 字段
  • 默认不存储 _all 字段
  • 默认搜索 _all 字段

如果从CPU性能及磁盘空间考虑,可以考虑可以完全禁用或基于每个字段自定义_all字段。

假设_all字段被禁用,则URI搜索请求、 query_stringsimple_query_string查询将无法将其用于查询。我们可以将它们配置为其他字段:通过定义 index.query.default_field 属性。

_source

这个字段用于存储原始的JSON文档内容,本身不会被索引,但是搜索的时候被返回。如果没有该字段,虽然还能正常搜索,但是返回的内容不知道对应的是什么。

示例:

GET /user/doc/_search?q=name

结果:

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "user",
        "_type": "doc",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "name": "this is test name",
          "age": 22,
          "job": "java",
          "intro": "the intro can not be searched by singal",
          "intro2": "去朝阳公园",
          "create_time": 1540047542
        }
      }
    ]
  }
}

搜索结果就包含_source字段,存储的是原始文档内容。如果被禁用,只知道有匹配内容,但是无法知道返回的是什么。所以需要谨慎关闭该字段。

如果想禁用该字段,可以在创建Mapping的时候,设置_:

{
  "mappings": {
    "_doc": {
      "_source": {
        "enabled": false
      }
    }
  }
}

_type

ElasticSearch里面有 index 和 type 的概念:index称为索引,type为文档类型,一个index下面有多个type,每个type的字段可以不一样。这类似于关系型数据库的 database 和 table 的概念。

但是,ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。所以后来ElasticSearch团队想去掉type,于是在6.x版本为了向下兼容,一个index只允许有一个type。

该字段再在6.0.0中弃用。在Elasticsearch 6.x 版本中创建的索引只能包含单个type。在5.x中创建的含有多个type的索引将继续像以前一样在Elasticsearch 6.x中运行。type 将在Elasticsearch 7.0.0中完全删除。

详见:https://www.elastic.co/guide/...

 

你可能感兴趣的:(Elasticsearch)