当前位置: 首页 > news >正文

ES_映射

一、 映射(Mapping)是什么?

简单来说,映射就像是关系型数据库中的表结构定义(Schema)。它定义了索引(Index)中的文档(Document)可以包含哪些字段(Field),以及每个字段的数据类型、格式、分词方式、是否索引、是否存储等属性。

核心思想: Elasticsearch是一个** schema-on-write **(写时定义模式)的系统。这意味着在数据被写入之前,最好就明确其结构,而不是像MongoDB这类 NoSQL 数据库是 schema-on-read(读时解析模式)。预先定义好映射,可以让ES更高效地处理、索引和存储数据。

映射的三大组成部分:

  1. 字段类型(Field datatypes): 定义字段的数据类型,如 text, keyword, long, integer, date, boolean, nested, object, geo_point 等。
  2. 元字段(Metadata fields): 用于处理文档的元信息,如 _index, _id, _source
  3. 映射参数(Mapping parameters): 精细化控制字段的索引和存储行为,如 index, analyzer, copy_to, fields 等。

二、 为什么映射如此重要?(架构师视角)

  1. 性能优化(Performance):

    • 正确的数据类型(如使用 keyword 而非 text 进行精确匹配和聚合)可以大幅提升查询和聚合速度。
    • 避免不必要的字段索引("index": false)可以节省磁盘空间和内存,减少索引大小,提升写入和检索效率。
  2. 存储效率(Storage Efficiency):

    • 选择合适的类型(如 integerlong 更省空间)和开启索引压缩(如 doc_values)可以减少磁盘占用。
  3. 功能正确性(Functionality Correctness):

    • 错误的映射会导致查询结果不符合预期。例如,一个本应做全文搜索的字段被错误地设置为 keyword 类型,将无法被分词搜索;一个日期字段被存为 text 类型,将无法进行时间范围查询。
  4. 避免后期重构(Avoiding Reindexing):

    • 映射一旦确定,虽然可以添加新字段,但不允许修改现有字段的类型。如果后期需要修改,必须进行 _reindex 操作(创建一个新索引并重建数据),这对于大数据量的集群来说成本极高。预先精心设计映射可以避免这种痛苦的重构过程。

三、 映射的核心概念详解

1. 字段类型(Field Data Types)
  • 核心类型:

    • text: 用于全文搜索的字符串类型,会被分词器(Analyzer)切分成倒排索引。适用于内容描述、正文等需要被搜索的文本。
    • keyword: 用于精确值过滤、排序和聚合的字符串类型,不会被分词。适用于状态码、标签、姓名、邮箱等。
    • date: 日期类型,可以指定格式。
    • long, integer, short, byte, double, float: 数值类型。
    • boolean: 布尔类型。
    • binary: 二进制类型。
    • range (如 integer_range, date_range): 范围类型。
  • 复杂类型:

    • object: 用于处理单个JSON对象。
    • nested: 非常重要的类型。用于处理对象数组,且需要数组中的对象被独立索引和查询。普通 object 数组中的对象在Lucene底层会被扁平化,导致跨对象的查询出现逻辑错误。nested 类型通过为数组中的每个对象创建独立的隐藏文档来解决这个问题。
    • flattened: 将整个子对象或数组映射为一个字段,其值被存储为 keyword 类型。适用于不确定子结构且不需要深层查询的场景,是 nested 的一种轻量级替代方案。
  • 专用类型:

    • geo_point: 存储经纬度坐标,用于地理位置搜索和距离计算。
    • ip: 存储IPv4/IPv6地址,支持IP范围查询。
    • completion: 用于实现自动补全(Suggesters)功能。
2. 关键映射参数(Mapping Parameters)
  • index: 控制字段是否被索引。默认为 true。如果设置为 false,则该字段不可被搜索,但仍会出现在 _source 中。
  • analyzer: 指定在索引和搜索时用于 text 字段的分词器。如 standard(默认), ik_smart, ik_max_word(中文常用), english
  • search_analyzer: 指定在搜索时使用的分词器,默认与 analyzer 一致。
  • fields: 多字段(Multi-fields)特性。允许对同一个字符串值以不同的方式索引多次,实现不同的目的。这是映射设计的精髓之一。
    • 例如:一个 product_name 字段可以同时被定义为 text 类型(用于全文搜索)和 keyword 类型(用于精确聚合和排序)。
    "product_name": {"type": "text","analyzer": "ik_max_word","fields": {"raw": { // 定义一个名为 raw 的子字段,类型为 keyword"type": "keyword"}}
    }
    
    查询时,使用 product_name 进行全文搜索,使用 product_name.raw 进行精确匹配或聚合。
  • copy_to: 将多个字段的值复制到一个组字段中,实现类似 _all 的跨字段搜索(ES7已移除 _all)。
  • doc_values: 默认开启。为 keyword, numeric, date, geo 等类型生成一个列式存储结构,用于排序、聚合和脚本访问。消耗磁盘空间,但极大提升聚合性能。
  • dynamic: 控制是否动态添加新字段。策略包括:
    • true (默认): 自动添加新字段。
    • false: 忽略新字段(不会被索引,但会出现在 _source 中)。
    • strict: 遇到新字段时抛出异常,拒绝文档写入。生产环境推荐使用 strictfalse 以避免“映射爆炸”(mapping explosion)

四、 结合实际案例:电商平台商品搜索

让我们以一个典型的电商平台商品数据模型为例,来设计其ES映射。

1. 需求分析

我们需要存储和搜索商品信息,核心功能包括:

  • 按商品名称、描述、分类进行全文搜索。
  • 按品牌、分类、店铺进行精确筛选和聚合。
  • 按价格、销量、上架时间进行排序和范围过滤。
  • 按商品属性(如颜色、尺寸、CPU型号)进行动态筛选和聚合。
  • 根据用户地理位置推荐附近的商品(基于店铺地址)。
2. 映射设计

我们将创建一个名为 products 的索引,并预先定义其映射。

PUT /products
{"settings": {"number_of_shards": 3,"number_of_replicas": 1,"analysis": {"analyzer": {"my_ik_analyzer": {"type": "custom","tokenizer": "ik_max_word"}}}},"mappings": {"dynamic": "strict", // 严格模式,防止未知字段污染映射"properties": {"id": {"type": "keyword"},"name": {"type": "text","analyzer": "my_ik_analyzer", // 使用IK中文分词器"fields": {"raw": {"type": "keyword" // 用于精确匹配,如作为聚合键}},"copy_to": "full_text" // 复制到全文搜索字段},"description": {"type": "text","analyzer": "my_ik_analyzer","copy_to": "full_text"},"brand": {"type": "keyword" // 品牌是典型的精确值字段},"category_id": {"type": "integer" // 分类ID用于关联查询,整数类型更高效},"category_path": {"type": "keyword" // 存储分类路径,如 "家电/空调/壁挂式"},"price": {"type": "scaled_float", // 缩放浮点型,避免浮点数精度问题"scaling_factor": 100},"sales_volume": {"type": "integer"},"is_on_shelf": {"type": "boolean"},"listing_time": {"type": "date","format": "epoch_millis" // 使用时间戳格式存储},"tags": {"type": "keyword" // 标签,用于精确过滤和聚合},"specs": { // 商品规格(动态属性),如 {"color": "红色", "size": "XL"}"type": "flattened" // 使用flattened类型,避免映射爆炸,且支持基本的键值查询},"store_info": { // 店铺信息,是一个对象"type": "object","properties": {"id": {"type": "keyword"},"name": {"type": "text","analyzer": "my_ik_analyzer","fields": {"raw": {"type": "keyword"}}},"location": { // 店铺地理位置"type": "geo_point"}}},"full_text": { // 用于跨字段全文搜索的组字段"type": "text","analyzer": "my_ik_analyzer"}}}
}
3. 使用方法与查询示例

a. 插入数据

POST /products/_doc/1001
{"id": "1001","name": "Apple iPhone 15 Pro Max 256GB 原色钛金属","description": "全新A17 Pro芯片,钛金属设计,强悍性能与卓越影像能力。","brand": "Apple","category_id": 1,"category_path": "手机通讯/手机/苹果手机","price": 8999.00,"sales_volume": 1500,"is_on_shelf": true,"listing_time": 1696118400000,"tags": ["新品", "优惠", "免息"],"specs": {"color": "原色钛金属","memory": "256GB","network": "5G"},"store_info": {"id": "s100","name": "Apple官方旗舰店","location": {"lat": 39.9042,"lon": 116.4074}}
}

b. 复杂查询示例

  • 全文搜索 + 过滤 + 聚合:搜索包含“苹果手机”且价格在5000-10000元之间的商品,并按品牌聚合。

    GET /products/_search
    {"query": {"bool": {"must": [{"match": {"full_text": "苹果手机"}}],"filter": [{"range": {"price": {"gte": 5000,"lte": 10000}}},{"term": {"is_on_shelf": true}}]}},"aggs": {"brands": {"terms": {"field": "brand"}}},"sort": [{"sales_volume": {"order": "desc"}}]
    }
    
  • 基于地理位置的查询:查找距离我(经纬度[116.40, 39.90])10公里以内的店铺的商品。

    GET /products/_search
    {"query": {"bool": {"filter": [{"geo_distance": {"distance": "10km","store_info.location": {"lat": 39.90,"lon": 116.40}}}]}}
    }
    
  • 查询特定规格:查询内存为“256GB”的商品。

    GET /products/_search
    {"query": {"match": {"specs": "256GB" // Flattened字段支持简单的匹配查询}}
    }
    

五、 最佳实践与总结

  1. 预先定义映射:切忌依赖动态映射。对于核心业务索引,务必在写入数据前通过 PUT /my_index { "mappings": { ... } } 创建好映射。
  2. 善用 keywordtext:明确字段是用来全文搜索还是精确匹配。绝大多数字符串字段都应使用 fields 配置为 text + keyword 多字段。
  3. 谨慎使用 nestednested 类型查询性能开销较大,仅在确实需要独立查询数组内对象时使用。如果关系简单,考虑使用 flattened
  4. 控制映射大小:使用 dynamic: strictfalse,避免无效字段无限增长。一个索引中字段过多(例如超过1000)会影响集群性能。
  5. 规划索引策略:结合ILM(Index Lifecycle Management),根据时间或数据量进行滚动索引(Rollover),这也能在一定程度上缓解映射不可修改的问题(因为新索引可以用新映射)。
  6. 进行映射评审:像评审数据库表结构一样,将重要的ES索引映射设计纳入技术评审流程。
http://www.dtcms.com/a/343323.html

相关文章:

  • Nacos-10--认识Nacos中的Raft协议(Nacos强一致性的实现原理)
  • VirtualBox 安装 Ubuntu Server 系统及 Ubuntu 初始配置
  • 区块链联邦学习思路一
  • 14、软件实现与测试
  • 实践题:智能健康监测系统设计方案
  • centos下安装Nginx(搭建高可用集群)
  • 亚马逊产品排名提升策略:从传统运营到AI驱动的智能化突破
  • 《信任链:幽灵签名》
  • 近端策略优化 (PPO) 算法深度解析
  • 智能求职推荐系统
  • mfc140u.dll文件是什么?解决mfc140u.dll文件丢失的有效解决方法分享
  • 密码管理中明文密码与空密码的危害与预防
  • 民国悬爱网剧《春迟》腾讯独播,石雨晴担纲联合出品人与联合制片人
  • Redis 主从复制(重点理解流程和原理)
  • Windows下服务封装
  • mac电脑使用(windows转Mac用户)
  • Java多线程编程——基础篇
  • STM32输入捕获相位差测量技术详解(基于TIM1复位模式)
  • Nacos 深度指南:从入门到高可用集群部署
  • ES6 面试题及详细答案 80题 (01-05)-- 基础语法与变量声明
  • C++宏的高级用法与元编程技巧
  • 数据结构青铜到王者第一话---数据结构基本常识(2)
  • 指数续创新高,期权的几种应对之策
  • 在线《相关性分析》
  • rs-fMRI_一篇文章中分析方法的梳理(翻译)
  • 职星学院企业培训系统:私有化部署赋能企业知识安全
  • 【鸿蒙开发】ArkTS 装饰器全解析:从 @Entry 到 @Observed 的全面指南
  • 资源对象深度解析:Pod生命周期与容器探针、Deployment滚动更新与回滚、StatefulSet有状态应用管理
  • 《MLB美职棒》美国国球是橄榄球还是棒球·棒球5号位
  • DAY44打卡