目录

目标

ES版本信息

官方文档

相关术语

实战

动态映射

静态映射

查看索引的映射

查看某字段的映射

约束字段的名称

约束字段的数量

约束字段名称的长度

字段合并

字段禁止被搜索

对null值进行搜索搜索

将字段添加到现有映射

Boost调整字段评分权重


目标

  • 了解mappings常用属性,通过设置mappings属性约束文档。本文介绍会一些常用的静态映射方法,包括:约束文档中字段的数量和名称,实现字段合并检索,字段禁止被搜索等。
  • 了解部分settings属性,这些属性和mappings属性关联较大,官网文档也将这些属性和mapping放在一起分析,所以本文也会做一些案例讲解。

ES版本信息

7.17.5


官方文档

Mappinghttps://www.elastic.co/guide/en/elasticsearch/reference/7.17/mapping.html


相关术语

动态映射

比如:在MySQL中需要建立数据库和表才可以插入数据,而ES不需要提前建立映射就能插入数据,因为索引(创建)文档时ES会自动识别属性的类型,这种机制称为动态映射。

动态映射文档类型
字符串

自动识别为text,还有子类型为keyword。

如果是日期格式则自动识别为date类型。

字符串类型的数字也可以自动识别为float和long类型,但是该配置默认关闭。

布尔值boolean
浮点数float
整数long
对象object,属性被properties包裹。
数组由最前面不为空的元素类型决定。
nullnull虽然可以索引文档,但是mappings忽略了对其类型的识别。

静态映射(也称为显示映射)

ES在索引文档前可以设置文档的字段名称、字段数量,分词器等,这称为静态映射。

字段合并

多个字段合并为一个新字段,但是该字段并不会出现在_source中。最常见的需求就是合并地址和英文姓名字段。检索条件可以直接对合并后的新字段进行匹配。

索引爆炸

settings下的属性。索引下的文档拥有过多字段会引发性能下降和内存问题,尤其是在负载高或资源少的集群中。通过设置index.mapping.total_fields.limit(文档字段数量最大值)来解决这一问题。字段和对象映射以及字段别名计入此限制。默认值为1000

字段的深度

settings下的属性。文档下有字段,如果这些字段都没有下级字段,则深度为1,如果有字段为对象类型,且对象类型里的字段没有下级字段,则深度为2。总的来说,深度实际上就是文档子目录的层数。通过设置index.mapping.depth.limit来控制文档字段的层级数量,默认为20。


实战

动态映射

第一步:直接索引一个文档。

PUT /mappings_test/_doc/1
{
  "name":"张三",
  "birthday":"2022-01-01",
  "boo":true,
  "source":34.35,
  "age":20,
  "favoriteNovels":["凡人修仙传","诛仙"],
  "examinationResults":{
    "English":98,
    "Chinese":100,
    "match":98.9
  }
}

第二步:查询自动映射的类型。

GET /mappings_test/_mapping

静态映射

查看索引的映射

GET /my-index-000001/_mapping

查看某字段的映射

GET /my-index-000001/_mapping/field/age

约束字段的名称

需求:创建索引,约束该索引只能有姓名、年龄、性别,成绩四个字段,设置成绩字段为对象类型且对象的属性不做数量的约束。

第一步:实现需求。

PUT /student
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "sex": {
        "type": "boolean"
      },
      "grade": {
        "type": "object",
        "dynamic": "true"
      }
    }
  }
}

第二步:索引以下3条文档,测试该索引字段数据的约束是否有效。结果发现王五这条文档索引失败,说明测试符合需求。

PUT /student/_doc/1
{
  "name":"张三",
  "age":12,
  "sex":true,
  "grade":{
    "English":98.5,
    "Math":100.0
  }
}

PUT /student/_doc/2
{
  "name":"李四",
  "sex":true,
  "grade":{
    "English":96.5,
    "Math":92.5,
    "Chinese":92.5
  }
}

PUT /student/_doc/3
{
  "name":"王五",
  "age":23,
  "birthday":"2022-01-01",
  "sex":true,
  "grade":{
    "Physics":96.5
  }
}

约束字段的数量

需求:约束文档的字段数量。需要注意:index.mapping.total_fields.limit属于settings属性,但是官网文档将其与映射限制设置放在了一起描述。所以我这里也做一个案例来讲解。

第一步:实现需求。

PUT /fields_num_db
{
  "settings": {
    "index.mapping.total_fields.limit": 6
  }
}

第二步:索引文档,测试文档字段数量的约束是否有效。发现前两条文档可以索引成功,最后一条文档索引失败。

PUT /fields_num_db/_doc/1
{
  "name":"张三"
}

PUT /fields_num_db/_doc/2
{
  "name": "李四",
  "address": {
    "province": "湖南省"
  }
}

PUT /fields_num_db/_doc/3
{
  "name":"李四",
  "address":{
    "province":"湖南省",
    "city":"岳阳市"
  }
}

约束字段的深度

需求:约束文档的字段的层级数量。需要注意:index.mapping.depth.limit属于settings属性,但是官网文档将其与映射限制设置放在了一起描述。所以我这里也做一个案例来讲解。

第一步:实现需求。

PUT /depth_num_db
{
  "settings": {
    "index.mapping.depth.limit": 2
  }
}

第二步:索引文档,发现第三条文档索引失败,因为第三条文档的深度是3,说明测试通过。

PUT /depth_num_db/_doc/1
{
  "name": "李四",
  "sex": false,
  "age": 12,
  "examination_results": {
    "Math": 98.5,
    "English": 100
  }
}

PUT /depth_num_db/_doc/2
{
  "name": "王五",
  "sex": false,
  "age": 12,
  "hobby": {
    "sports":["跑步","篮球"]
  }
}

PUT /depth_num_db/_doc/3
{
  "name": "王五",
  "sex": false,
  "age": 12,
  "hobby": {
    "novel":{
      "凡人修仙传":"忘语",
      "天龙八部":"金庸"
    }
  }
}

约束字段名称的长度

需求:需要注意:index.mapping.field_name_length.limit属于settings属性,但是官网文档将其与映射限制设置放在了一起描述。所以我这里也做一个案例来讲解。

第一步:实现需求。

PUT /name_length_db
{
  "settings": {
    "index.mapping.field_name_length.limit": 50
  }
}

第二步:索引文档,测试通过。

PUT /name_length_db/_doc/1
{
  "name": "张三"
}

PUT /name_length_db/_doc/2
{
  "name": "李四",
  "a12345678901234567890123456789012345678901234567890":"1"
}

字段合并

需求:创建索引,对省市县字段进行合并。

第一步:实现需求。

PUT /address_list
{
  "mappings": {
    "properties": {
      "province": {
        "type": "text",
        "copy_to": "fullAddress"
      },
      "city": {
        "type": "text",
        "copy_to": "fullAddress"
      },
      "county": {
        "type": "text",
        "copy_to": "fullAddress"
      }
    }
  },
  "settings": {
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }
}

第二步:批量索引文档。

PUT /address_list/_bulk
{ "index": { "_id": "1"} }  
{"province": "湖南省","city": "长沙市","county":"天心区"}
{ "index": { "_id": "2"} }  
{"province": "湖南省","city": "长沙市","county":"芙蓉区"}
{ "index": { "_id": "3"} }  
{"province": "广东省","city": "广州市","county":"白云区"}
{ "index": { "_id": "4"} }  
{"province": "湖北省","city": "武汉市","county":"江夏区"}

第三步:用ik分词器查看分词效果。这里以查看"湖南省长沙市天心区"为例。

POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "湖南省长沙市天心区"
}

第四步:检索文档,测试fullAddress字段是否有效。这里以查看"湖南天心"为例,结果查不到,后来用ik分词器查看,原来分词出现了"南天",而"湖南省长沙市天心区"分词以后没有南天,所以在用"operator": "and"条件查询时无效。反之,如果查询条件是"湖南省天心"时,就可以查到结果。

GET /address_list/_search
{
  "query": {
    "match": {
      "fullAddress": {
        "query": "湖南天心",
        "operator": "and"
      }
    }
  }
}
GET /address_list/_search
{
  "query": {
    "match": {
      "fullAddress": {
        "query": "湖南省天心",
        "operator": "and"
      }
    }
  }
}

字段禁止被搜索

需求:创建索引,约束该索引下的文档中age字段不能被搜索。

第一步:实现需求。

PUT /ban_db
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "sex": {
        "type": "boolean"
      },
      "age": {
        "type": "long",
        "index":false
      }
    }
  }
}

第二步:索引几条文档。

PUT /ban_db/_bulk
{"index":{"_id":"1"}}
{"name":"孟浩然","sex":false,"age":12}
{"index":{"_id":"2"}}
{"name":"陈永生","sex":true,"age":23}
{"index":{"_id":"3"}}
{"name":"李长春","sex":false,"age":15}
{"index":{"_id":"4"}}
{"name":"陈天相","sex":true,"age":20}

第三步:根据条件查询文档。发现当搜索条件为age时报错,提示无法在该字段上搜索,需求测试通过。

GET /ban_db/_doc/1

GET /ban_db/_search
{
  "query": {
    "term": {
      "sex": {
        "value": true
      }
    }
  }
}

GET /ban_db/_search
{
  "query": {
    "term": {
      "age": {
        "value": 12
      }
    }
  }
}

对null值进行搜索搜索

需求:只有字段为keyword类型时才可以对null值进行搜索。开发环境最常见的就是设置name为keyword类型,下面就用这个为案例进行演示。

第一步:实现需求。name属性设置null_value=value_is_null,其中value_is_null可以自定义,因为它的实际含义就是在精确搜索时,匹配条件值为value_is_null时表示搜索name为null值。

PUT /null_db
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword",
        "null_value": "value_is_null"
      },
      "sex": {
        "type": "boolean"
      },
      "age": {
        "type": "long"
      }
    }
  },
  "settings": {
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }
}

第二步:索引几条文档。

PUT /null_db/_bulk
{"index":{"_id":"1"}}
{"name":"null","sex":false,"age":12}
{"index":{"_id":"2"}}
{"name":"陈永生","sex":true,"age":23}
{"index":{"_id":"3"}}
{"name":null,"sex":false,"age":15}
{"index":{"_id":"4"}}
{"name":"陈天相","sex":true,"age":20}

第三步:搜索name为null的文档。发现只搜索出了id=3的文档,说明需求测试通过。

GET /null_db/_search
{
  "query": {
    "term": {
      "name": {
        "value": "value_is_null"
      }
    }
  }
}

将字段添加到现有映射

需求:在一个已经定义好的索引中加入新的字段。注意:如果要变更现有字段,大家可以参考我的另一篇关于索引重建的文档。

第一步:创建索引。

PUT /my-index-000001
{
  "mappings": {
    "dynamic": "strict", 
    "properties": {
      "name": {
        "type": "keyword",
        "null_value": "value_is_null"
      },
      "sex": {
        "type": "boolean"
      },
      "age": {
        "type": "long"
      }
    }
  },
  "settings": {
    "index": {
      "analysis.analyzer.default.type": "ik_max_word"
    }
  }
}

第二步:实现需求。

PUT /my-index-000001/_mapping
{
  "properties": {
    "weight": {
      "type": "float"
    },
    "height": {
      "type": "float"
    }
  }
}

第三步:查看映射。

GET /my-index-000001/_mapping

Boost调整字段评分权重

分析:比如文章的标题和内容,按照业务来看,明显应该是标题评分权重大于内容评分权重。

需求:将标题评分增加1倍。

第一步:新增测试数据。实现标题评分增加到原来的10倍。

PUT /article_db
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "boost": 10
      },
      "content": {
        "type": "text"
      }
    }
  }
}

PUT /article_db/_bulk
{"index":{"_id":"1"}}
{"title":"公园里有一只棕色的狐狸","content":"这只狐狸很好看。"}
{"index":{"_id":"2"}}
{"title":"棕色的兔子","content":"公园里有一只棕色的兔子,它比棕色的狐狸更好看。"}

第二步:搜索验证。发现文档2排在文档1的前面,此时如果将权重取消,则发现结果与现在正好相反,这说明Boost生效了,评分权重更偏向标题字段。

GET /article_db/_search
{
  "query": {
    "multi_match": {
      "query": "棕色的狐狸",
      "fields": [
        "title",
        "content"
      ]
    }
  }
}

等同于这种方法(推荐)

GET /article_db/_search
{
  "query": {
    "multi_match": {
      "query": "棕色的狐狸",
      "fields": [
        "title^10",
        "content"
      ]
    }
  }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐