Mapping

本文详细介绍了Elasticsearch的mapping,包括mapping类型、字段数据类型(如text、keyword、date等)、动态mapping、详尽mapping及如何更新字段mapping。重点讨论了如何定义字符串字段的全文搜索、数字类型的索引以及地理信息数据类型。还提到了动态mapping和自定义详尽mapping的重要性,以及废弃的mapping types。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mapping是定义文档及其字段是如何存储和索引的程序。例如,使用mapping定义:

  • 哪个字符串字段应该视为全文字段
  • 哪个字段包含数字,日期,或地理位置
  • 日期的格式
  • 自定义规则来控制动态添加字段

mapping type

每个索引都有mapping type来决定文档如何被索引。mapping type包含:

  • meta-fields: 比如_index, _type, _id, _source字段,用来定制文档相关的元数据
  • fields or properties:相关文档的字段列表或者properties

字段数据类型

每个字段都有数据类型,可以是如下:

  • 简单的类型:text, keyword, date, long, double, boolean, ip
  • 支持JSON这种层次结构的:object, nested
  • 专门的类型:geo_point, geo_shape, completion

根据不同的目的以不同的方式来索引相同的字段通常很有用。比如,同样的字段可以索引为text类型以便进行全文搜索,也可以作为keyword类型用来排序或聚合。或者同样的值使用不同的分词器。

大部分字段都支持fields参数的多字段搜索。

核心数据类型

  • 字符串

    PUT my_index
    {
      "mappings": {
        "properties": {
          "full_name": {
            "type":  "text"
          }
        }
      }
    }
    
    • text 用于全文索引,会被分词处理。适用于文章内容,产品介绍之类的信息。可以接收以下参数:

      • analyzer 指定分词器,同时适用于索引时和搜索时(除非被search_analyzer覆盖),默认值是索引默认的分词器,或者standard分词器
      • boost 字段级别的查询时提升(权重),接收浮点数,默认是1.0
      • eager_global_ordinals 刷新时是否重新加载全局顺序?默认是false。建议对经常用于词条聚合的此段启动该特性。
      • fielddata 该字段是否能使用内存字段数据用来排序,聚合,或者脚本计算?默认false
      • fielddata_frequency_filter 专家设置:当fielddata启用时,是否允许决定哪些值被载入内存,默认情况下加载所有值
      • fields 多字段(multi-fields)允许出于不同的目的以多种方式来索引相同的字段,比如一个字段用于搜索,一个多字段用于排序和聚合,或者对同样的字符串使用不同的分词器
      • index 字段是否可被搜索,默认true
      • index_options 索引中应该存储什么信息用于搜索和高亮,默认是positions
      • index_prefixes 如果启用,2~5个字符的词条前缀将会被索引为一个单独的字段,有助于提高前缀搜索的效率。
      • index_phrases 如果允许,词组会被索引为单独的字段。这使得精确的短语查询更高效。注意,只有当停用词没有被移除时,这个才最有效,因为包含停用词的短语不会使用子字段,而是使用标准的短语查询。默认值是false
      • norms 打分时是否考虑字段长度,默认true
      • position_increment_gap 略
      • store 字段值是否在_source字段外,被独立存储和检索,默认false
      • search_analyzer 指定搜索时的分词器,默认是analyzer 参数的设置
      • search_quote_analyzer 没啥用
      • similarity 使用哪种打分算法,默认是BM25
      • term_vector 略
    • keyword 关键词,适用于标签,状态码,邮件地址,域名,商标等。用于过滤,排序,和聚合,关键词只支持精确搜索。

      PUT my_index
      {
        "mappings": {
          "properties": {
            "tags": {
              "type":  "keyword"
            }
          }
        }
      }
      

      支持的参数如下:

      • ignore_above 默认是2147483647,超过这一长度的字符串无法索引。但是默认的动态mapping会覆盖这个值为ignore_above:256
      • 其他和text类似,具体参见官网
  • 数字

    • long -2^63 ~ 2^63-1

    • integer -2^31 ~ 2^31-1

    • short -32768 ~ 32768

    • byte -128 ~ 127

    • double 64位双精度浮点数

    • float 32位双精度浮点数

    • half_float 16位双精度浮点数

    • scaled_float 略

      PUT my_index
      {
        "mappings": {
          "properties": {
            "number_of_bytes": {
              "type": "integer"
            },
            "time_in_seconds": {
              "type": "float"
            },
            "price": {
              "type": "scaled_float",
              "scaling_factor": 100
            }
          }
        }
      }
      
    • 数字类型的字段支持以下参数:

      • coerce 强制转换字符串为数字,截断分数为整数,默认是true
      • 其他参数参考官网
  • date,JSON没有日期类型,因此ES中的日期可以是

    • 包含日期格式的字符串,比如:"2015-01-01" or "2015/01/01 12:10:30"
    • 时间的毫秒数
    • 时间的整数

    在ES内部,日期会被转换为UTC时间(如果指定了时区),并且存储为代表时间毫秒数的长整数。对于日期的查询会被转化为对这个长整数的范围查询,结果再转化为以该字段定义的日期格式的字符串。日期格式可以自定义,如果没有指定format,会使用如下默认值:

    "strict_date_optional_time||epoch_millis"
    

    这意味它可以接受strict_date_optional_time支持的格式,或者毫秒数,例如:

    PUT my_index
    {
      "mappings": {
        "properties": {
          "date": {
            "type": "date" // 不指定format,那就使用上面提到的默认值
          }
        }
      }
    }
    
    PUT my_index/_doc/1
    { "date": "2015-01-01" }   // 纯日期
    
    PUT my_index/_doc/2
    { "date": "2015-01-01T12:10:30Z" } //日期+时间
    
    PUT my_index/_doc/3
    { "date": 1420070400001 }  // 毫秒数
    
    GET my_index/_search
    {
      "sort": { "date": "asc"} 
    }
    

    自定义多种日期格式:

    PUT my_index
    {
      "mappings": {
        "properties": {
          "date": {
            "type":   "date",
            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
          }
        }
      }
    }
    
  • 布尔

    • boolean: true, false
  • 二进制

    • binary

      PUT my_index
      {
        "mappings": {
          "properties": {
            "name": {
              "type": "text"
            },
            "blob": {
              "type": "binary"
            }
          }
        }
      }
      
      PUT my_index/_doc/1
      {
        "name": "Some binary blob",
        "blob": "U29tZSBiaW5hcnkgYmxvYg=="   // base64编码后的二进制
      }
      
  • 范围

    • integer_range: -2^31 ~ 2^31-1
    • float_range
    • long_range
    • double_range
    • date_range

    示例:范围字段在索引文档时,需要使用gte, lte

    PUT range_index
    {
      "settings": {
        "number_of_shards": 2
      },
      "mappings": {
        "properties": {
          "expected_attendees": {
            "type": "integer_range"
          },
          "time_frame": {
            "type": "date_range", 
            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
          }
        }
      }
    }
    
    PUT range_index/_doc/1?refresh
    {
      "expected_attendees" : {   // 索引文档时需要指定范围
        "gte" : 10,
        "lte" : 20
      },
      "time_frame" : { 
        "gte" : "2015-10-31 12:00:00", 
        "lte" : "2015-11-01"
      }
    }
    

复杂数据类型

  • object 对象

    JSON文档本身就是一种结构话的数据,比如:

    PUT my_index/_doc/1
    { 
      "region": "US",
      "manager": { // manager对象
        "age":     30,
        "name": { 
          "first": "John",
          "last":  "Smith"
        }
      }
    }
    

    ES内部会将以上文档索引为扁平的键值对,类似于:

    {
      "region":             "US",
      "manager.age":        30,
      "manager.name.first": "John",
      "manager.name.last":  "Smith"
    }
    

    以上文档的mapping如下:

    PUT my_index
    {
      "mappings": {
        "properties": { 
          "region": {
            "type": "keyword"
          },
          "manager": { // manager作为内部对象,可以有自己的age, name
            "properties": {
              "age":  { "type": "integer" },
              "name": { 
                "properties": {
                  "first": { "type": "text" },
                  "last":  { "type": "text" }
                }
              }
            }
          }
        }
      }
    }
    

    object字段支持参数如下:

    • dynamic 是否支持对象的properties动态增加字段,默认"true"
    • enabled 是否允许对象字段直接解析索引JSON,默认"true"
  • nested 嵌套对象,用来支持多个对象构成的数组,mapping如下:

    PUT my_index
    {
      "mappings": {
        "properties": {
          "user": {
            "type": "nested" 
          }
        }
      }
    }
    

    索引文档:

    PUT my_index/_doc/1
    {
      "group" : "fans",
      "user" : [
        {
          "first" : "John",
          "last" :  "Smith"
        },
        {
          "first" : "Alice",
          "last" :  "White"
        }
      ]
    }
    

    查询示例1:

    GET my_index/_search
    {
      "query": {
        "nested": {
          "path": "user",
          "query": {
            "bool": {
              "must": [
                { "match": { "user.first": "Alice" }},
                { "match": { "user.last":  "Smith" }} 
              ]
            }
          }
        }
      }
    }
    

    以上查询无法匹配任何结果,因为"Alice"和"Smith"不在同一个嵌套对象中。

    查询示例2:

    GET my_index/_search
    {
      "query": {
        "nested": {
          "path": "user",
          "query": {
            "bool": {
              "must": [
                { "match": { "user.first": "Alice" }},
                { "match": { "user.last":  "White" }} 
              ]
            }
          },
          "inner_hits": { // 匹配的嵌套文档进行高亮
            "highlight": {
              "fields": {
                "user.first": {}
              }
            }
          }
        }
      }
    }
    

    由于"Alice"和"White"在同一个嵌套对象中,因此可以查询可以匹配。

地理信息数据类型

  • geo_point
  • geo_shape

专门数据类型

  • ip

  • completion 自动完成(搜索建议)

  • token_count:字符串中的词条的数量

  • murmur3 索引时计算内容的哈希值并存储在索引中

  • annotated-text 索引包含特殊标记的文本(用于标识命名实体)

  • join 定义索引中文档的父子关系

    PUT my_index
    {
      "mappings": {
        "properties": {
          "my_join_field": { 
            "type": "join",
            "relations": {
              "question": "answer"  // question和answer是父子关系
            }
          }
        }
      }
    }
    
  • alias 已存在字段定义别名

  • rank 记录数字特征来提高查询的命中

  • vector 向量

数组

ES中,数组不需要专门的字段。默认情况下,任何字段都可以包括零个或多个值,但是所有的值必须具有相同的数据类型。

动态mapping

字段和mapping类型不需要事先定义,因此在索引文档时,新字段的名字将会自动添加(可以添加到根字段,或者是object和nested子字段)

详尽mapping

比起Elasticsearch的“猜测”,你更清楚你的数据。所以一开始可以用动态mapping,到某个阶段后,你可以自己定制mapping。

你可以在创建索引(集)时创建字段mapping,然后通过PUT mapping API来向已经存在的索引(集)增加字段。

更新现存字段的mapping

除了文档之外,现存字段的mapping无法更新。更新字段意味着已经索引的文档会失效。相反,你应该用正确的mapping创建一个新的索引,然后reindex数据到新的索引中。如果你只是想重命名某个字段而不改变mapping,可以使用alias字段。

示例

创建索引时指定mapping:

PUT my_index 
{
  "mappings": {
    "properties": {
      "title":    { "type": "text"  }, 
      "name":     { "type": "text"  }, 
      "age":      { "type": "integer" },  
      "created":  {
        "type":   "date", 
        "format": "strict_date_optional_time||epoch_millis"
      }
    }
  }
}

废除mapping types

7.0之后废除,原先需要指定type的地方,都用_doc代替。

由于第一版ES中,所有的文档存储在单个索引中,比如user类型的文档和blog类型的文档,他们的数据结构不同,为了区分,就分别定义了user类型,和blog类型。每个文档都有一个_type元字段来标明类型,搜索时也需要指定类型名。另外,在单个索引中,不同的类型的文档可以拥有相同的_id值,因此要唯一标识一个资源,需要通过_type_id

更多信息查看具体查看官网

mapping参数

  • normalizer 相当于keyword字段的analyzer,只不过保证语义分析链最终返回一个词条

  • analyzer 略

  • boost 字段权重,默认1.0

  • copy_to 将多个字段的值放到一个字段

    PUT my_index
    {
      "mappings": {
        "properties": {
          "first_name": {
            "type": "text",
            "copy_to": "full_name" 
          },
          "last_name": {
            "type": "text",
            "copy_to": "full_name" 
          },
          "full_name": {
            "type": "text"
          }
        }
      }
    }
    
  • fields 对同一字段指定不同的数据类型和分词器

    PUT my_index
    {
      "mappings": {
        "properties": {
          "city": {
            "type": "text",
            "fields": {
              "raw": { 
                "type":  "keyword"
              }
            }
          }
        }
      }
    }
    

    city用于全文检索,city.raw作为keyword,可以支持排序聚合

  • completion

  • 其他略,参考text数据类型的参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值