MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch映射属性设置方法

2022-02-077.2k 阅读

ElasticSearch 映射基础

映射的概念

在 Elasticsearch 中,映射(Mapping)是定义文档及其包含的字段如何存储和索引的过程。它类似于关系型数据库中的表结构定义,但更为灵活。映射定义了文档的字段名、字段的数据类型(如文本、数字、日期等),以及如何对这些字段进行索引,比如是否分词、是否存储等。

映射的重要性

  1. 数据存储与检索优化:合理的映射设置可以确保数据以高效的方式存储在 Elasticsearch 中,并且能够快速地被检索到。例如,对于文本字段,如果设置为不分词存储,在进行全文搜索时就无法得到预期的结果;而如果对数值字段进行不必要的分词,会浪费存储空间且影响检索性能。
  2. 数据一致性:映射保证了相同类型的文档具有一致的结构。这使得在索引和查询文档时,系统能够按照预期的方式处理数据,避免因文档结构不一致而导致的错误。

映射类型的演变

在早期版本的 Elasticsearch 中,一个索引可以包含多种映射类型(Type),类似于关系型数据库中一张表可以有不同类型的行。但从 Elasticsearch 7.0 版本开始,逐步废弃了这种多映射类型的设计,到 8.0 版本完全移除。现在一个索引只支持一种映射,这使得索引结构更加简洁明了,减少了因多类型带来的复杂性和潜在问题。

核心映射属性设置

字段数据类型

  1. 文本类型(text)
    • 特点:用于存储长文本,默认会进行分词处理。例如,一个博客文章的正文内容就适合使用 text 类型。
    • 代码示例
{
  "mappings": {
    "properties": {
      "article_body": {
        "type": "text"
      }
    }
  }
}
  • 分词细节:Elasticsearch 使用分析器(Analyzer)对 text 类型字段进行分词。默认的分析器是 standard 分析器,它会根据 Unicode 文本分割规则将文本拆分成词项(Term)。例如,对于文本 “Elasticsearch is a great search engine”,standard 分析器会将其拆分成 “elasticsearch”、“is”、“a”、“great”、“search”、“engine” 等词项。
  1. 关键词类型(keyword)
    • 特点:用于存储精确值,如标识符、标签、状态码等,不会进行分词。适合用于过滤、排序和聚合操作。
    • 代码示例
{
  "mappings": {
    "properties": {
      "product_id": {
        "type": "keyword"
      }
    }
  }
}
  • 应用场景:在电商系统中,产品的 SKU(Stock Keeping Unit)就可以定义为 keyword 类型。这样在查询特定 SKU 的产品时,可以直接进行精确匹配,而不需要进行分词处理。
  1. 数值类型
    • 整数类型:包括 byte(8 位有符号整数)、short(16 位有符号整数)、integer(32 位有符号整数)、long(64 位有符号整数)。根据数据的取值范围选择合适的类型可以节省存储空间。
    • 浮点数类型float(单精度 32 位浮点数)、double(双精度 64 位浮点数)。此外,还有 half_float(16 位半精度浮点数)和 scaled_float(适合需要固定比例缩放的浮点数)。
    • 代码示例
{
  "mappings": {
    "properties": {
      "product_price": {
        "type": "float"
      },
      "product_stock": {
        "type": "integer"
      }
    }
  }
}
  • 精度与存储:对于数值类型,要注意精度问题。例如,float 类型在某些情况下可能会有精度损失,而 double 类型精度更高但占用更多空间。scaled_float 类型通过指定一个缩放因子,可以在保证一定精度的同时节省存储空间。比如,对于价格字段,如果所有价格都是以分为单位,且精度要求不高,可以使用 scaled_float 并设置缩放因子为 100。
  1. 日期类型(date)
    • 特点:用于存储日期和时间信息。Elasticsearch 支持多种日期格式,包括 ISO 8601 格式(如 “2023 - 10 - 05T14:30:00Z”),也支持自定义日期格式。
    • 代码示例
{
  "mappings": {
    "properties": {
      "article_published_date": {
        "type": "date"
      }
    }
  }
}
  • 日期格式处理:可以通过 format 参数指定日期格式。例如,如果日期存储格式为 “yyyy - MM - dd”,可以这样设置:
{
  "mappings": {
    "properties": {
      "article_published_date": {
        "type": "date",
        "format": "yyyy - MM - dd"
      }
    }
  }
}
  • 日期运算与查询:Elasticsearch 支持对日期类型字段进行各种运算和查询,如查找某个时间段内发布的文章。可以使用 range 查询来实现,例如:
{
  "query": {
    "range": {
      "article_published_date": {
        "gte": "2023 - 01 - 01",
        "lte": "2023 - 12 - 31"
      }
    }
  }
}
  1. 布尔类型(boolean)
    • 特点:用于存储 truefalse 值,常用于表示逻辑状态,如产品是否上架、用户是否激活等。
    • 代码示例
{
  "mappings": {
    "properties": {
      "product_is_on_sale": {
        "type": "boolean"
      }
    }
  }
}
  1. 二进制类型(binary)
    • 特点:用于存储二进制数据,如图片、视频等。但需要注意的是,Elasticsearch 本身并不擅长处理二进制数据的内容检索,通常用于存储文件的元数据等相关信息。
    • 代码示例
{
  "mappings": {
    "properties": {
      "image_file": {
        "type": "binary"
      }
    }
  }
}

索引设置

  1. 是否索引(index)
    • 作用index 属性决定了字段是否被索引。如果设置为 false,该字段将不会被索引,也就无法通过该字段进行搜索,但仍然可以存储在文档中。
    • 代码示例
{
  "mappings": {
    "properties": {
      "article_content_raw": {
        "type": "text",
        "index": false
      }
    }
  }
}
  • 应用场景:对于一些只需要存储但不需要搜索的信息,如文章的原始备份内容,设置 indexfalse 可以节省索引空间。
  1. 索引选项(index_options)
    • 适用类型:主要用于 text 类型字段。
    • 选项说明
      • docs:只索引文档号,适合用于过滤,但不适合全文搜索。
      • freqs:索引文档号和词频,词频信息可用于相关性算分。
      • positions:除了文档号和词频,还索引词项的位置信息,可用于短语搜索。
      • offsets:除了以上信息,还索引词项在原始文本中的偏移量,主要用于高亮显示。
    • 代码示例
{
  "mappings": {
    "properties": {
      "article_title": {
        "type": "text",
        "index_options": "positions"
      }
    }
  }
}
  • 选择依据:如果只需要对文本字段进行简单的过滤,docs 选项就足够了,这样可以节省存储空间。如果需要进行全文搜索并考虑相关性算分,freqs 是一个不错的选择。对于需要支持短语搜索的场景,positions 选项是必需的。而如果要实现精确的高亮显示,就需要 offsets 选项。

存储设置

  1. 是否存储(store)
    • 作用store 属性决定了字段的值是否会被单独存储。默认情况下,Elasticsearch 会将文档的原始内容存储在 _source 字段中,因此对于大多数情况,不需要单独设置 storetrue。只有在需要直接从索引中获取字段值而不通过 _source 字段时,才设置 storetrue
    • 代码示例
{
  "mappings": {
    "properties": {
      "article_summary": {
        "type": "text",
        "store": true
      }
    }
  }
}
  • 注意事项:设置 storetrue 会增加存储空间,因为字段值会被额外存储一份。而且,即使设置了 store,如果需要获取整个文档内容,还是建议从 _source 字段获取,因为 _source 包含了文档的所有原始信息。
  1. 压缩设置
    • 压缩方式:Elasticsearch 支持对存储的数据进行压缩,以节省磁盘空间。常用的压缩算法有 LZ4DEFLATE
    • 设置方法:在索引级别设置压缩方式,例如:
{
  "settings": {
    "index": {
      "codec": "lz4"
    }
  }
}
  • 性能影响:不同的压缩算法在压缩比和压缩/解压缩速度上有所不同。LZ4 算法速度较快,但压缩比相对较低;DEFLATE 算法压缩比更高,但压缩/解压缩速度较慢。在选择压缩算法时,需要根据实际情况权衡磁盘空间和性能的需求。

复杂映射设置

多字段设置

  1. 多字段的概念:一个字段可以以多种方式进行索引,以满足不同的查询需求。例如,对于一个文本字段,既可以进行全文搜索,也可以进行精确匹配搜索。通过多字段设置,可以为同一个字段定义不同的子字段,每个子字段有不同的映射设置。
  2. 代码示例
{
  "mappings": {
    "properties": {
      "article_title": {
        "type": "text",
        "fields": {
          "raw": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
  • 应用场景:在上述示例中,article_title 字段是普通的 text 类型,用于全文搜索。而 article_title.raw 子字段是 keyword 类型,用于精确匹配,比如在查询特定标题的文章时,可以使用 article_title.raw 字段进行精确查询。

对象类型(object)

  1. 对象类型的作用:用于表示 JSON 格式中的对象结构。在 Elasticsearch 中,文档本身就是一个 JSON 对象,而对象类型可以用于表示文档中的嵌套对象。
  2. 代码示例
{
  "mappings": {
    "properties": {
      "author": {
        "type": "object",
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          },
          "email": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
  • 存储与查询:Elasticsearch 将对象类型的字段扁平化存储。例如,上述 author 对象在存储时,会将 author.nameauthor.ageauthor.email 作为独立的字段进行索引。在查询时,可以通过嵌套路径进行查询,如查询作者名为 “John” 的文档:
{
  "query": {
    "match": {
      "author.name": "John"
    }
  }
}

嵌套类型(nested)

  1. 与对象类型的区别:虽然嵌套类型也是用于表示嵌套结构,但它与对象类型有本质区别。对象类型在存储时会扁平化处理,这可能导致在处理嵌套数组时出现数据关联问题。而嵌套类型会将每个嵌套文档单独索引,保持嵌套文档之间的独立性。
  2. 代码示例
{
  "mappings": {
    "properties": {
      "comments": {
        "type": "nested",
        "properties": {
          "comment_text": {
            "type": "text"
          },
          "comment_author": {
            "type": "text"
          },
          "comment_date": {
            "type": "date"
          }
        }
      }
    }
  }
}
  • 应用场景:在博客文章的评论场景中,如果评论是一个数组,每个评论包含评论内容、评论作者和评论日期等信息,使用嵌套类型可以确保每个评论的信息在索引和查询时保持正确的关联。例如,查询评论作者为 “Alice” 的所有文章:
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "match": {
          "comments.comment_author": "Alice"
        }
      }
    }
  }
}

地理类型

  1. 地理点类型(geo_point)
    • 作用:用于存储地理坐标(经度和纬度),以便进行地理空间查询,如查找某个位置附近的文档。
    • 代码示例
{
  "mappings": {
    "properties": {
      "store_location": {
        "type": "geo_point"
      }
    }
  }
}
  • 坐标格式:可以以多种格式提供地理坐标,如 “latitude,longitude”(例如 “37.7749,-122.4194”),也可以使用对象格式 {"lat": 37.7749, "lon": -122.4194}
  • 地理空间查询:可以使用 geo_distance 查询来查找某个位置一定距离内的文档。例如,查找距离坐标 “37.7749,-122.4194” 10 公里内的商店:
{
  "query": {
    "geo_distance": {
      "distance": "10km",
      "store_location": {
        "lat": 37.7749,
        "lon": -122.4194
      }
    }
  }
}
  1. 地理形状类型(geo_shape)
    • 作用:用于存储更复杂的地理形状,如多边形、线等。适用于需要进行复杂地理空间分析的场景,如查找某个区域内的所有兴趣点。
    • 代码示例
{
  "mappings": {
    "properties": {
      "city_boundary": {
        "type": "geo_shape"
      }
    }
  }
}
  • 形状表示:地理形状通常以 GeoJSON 格式表示。例如,一个多边形可以这样表示:
{
  "type": "Polygon",
  "coordinates": [
    [
      [100.0, 0.0],
      [101.0, 0.0],
      [101.0, 1.0],
      [100.0, 1.0],
      [100.0, 0.0]
    ]
  ]
}
  • 查询操作:可以使用 geo_shape 查询来查找与某个地理形状相交或包含的文档。例如,查询位于某个城市边界内的所有建筑物:
{
  "query": {
    "geo_shape": {
      "city_boundary": {
        "shape": {
          "type": "Polygon",
          "coordinates": [
            [
              [100.0, 0.0],
              [101.0, 0.0],
              [101.0, 1.0],
              [100.0, 1.0],
              [100.0, 0.0]
            ]
          ]
        },
        "relation": "within"
      }
    }
  }
}

动态映射与静态映射

动态映射

  1. 动态映射原理:当 Elasticsearch 接收到一个新文档时,如果索引中不存在该文档类型的映射,Elasticsearch 会根据文档的内容自动推断字段的数据类型,并生成相应的映射,这就是动态映射。
  2. 动态映射规则
    • 对于 JSON 中的字符串,如果字符串看起来像日期,Elasticsearch 会尝试将其映射为 date 类型。例如,“2023 - 10 - 05” 可能会被映射为 date 类型。
    • 对于数值类型,Elasticsearch 会根据数值的大小自动选择合适的数值类型,如 integerlong
    • 对于布尔值 truefalse,会被映射为 boolean 类型。
    • 对于 JSON 对象,会被映射为 object 类型。
  3. 动态映射控制:可以通过 dynamic 属性来控制动态映射的行为。
    • true(默认值):自动添加新字段到映射。
    • false:忽略新字段,不会将新字段添加到映射中,但新字段的值仍然会存储在 _source 字段中。
    • strict:如果遇到新字段,抛出异常,拒绝索引文档。
    • 代码示例
{
  "mappings": {
    "dynamic": "false",
    "properties": {
      "existing_field": {
        "type": "text"
      }
    }
  }
}

静态映射

  1. 静态映射定义:与动态映射相反,静态映射是指在索引创建之前,手动定义好所有字段的映射。这样可以确保索引的结构符合预期,避免因动态映射可能带来的意外情况。
  2. 优势与适用场景
    • 优势:静态映射可以更好地控制索引结构,确保数据的一致性和可预测性。在生产环境中,对于数据质量要求较高、查询性能要求严格的场景,静态映射是首选。
    • 适用场景:例如在金融行业的交易记录索引中,字段的类型和格式都有严格的规定,使用静态映射可以保证数据的准确性和稳定性。
  3. 代码示例
{
  "mappings": {
    "properties": {
      "transaction_id": {
        "type": "keyword"
      },
      "transaction_amount": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "transaction_date": {
        "type": "date",
        "format": "yyyy - MM - dd HH:mm:ss"
      }
    }
  }
}

映射的更新与管理

映射更新的限制

  1. 字段类型限制:一旦字段被索引,通常不能直接更改其数据类型。例如,不能将一个已索引的 text 类型字段改为 keyword 类型。这是因为不同的数据类型有不同的索引方式,更改类型可能导致已索引的数据无法正确检索。
  2. 索引结构限制:在 Elasticsearch 中,不能直接向已有的映射中添加新的对象类型或嵌套类型字段,同时保持现有数据的一致性。如果需要添加新的复杂类型字段,可能需要重建索引。

部分更新映射

  1. 新增字段:可以在现有映射中添加新的字段,只要这些字段的数据类型与动态映射规则兼容(如果动态映射开启)。例如,对于一个已存在的索引,可以添加新的文本字段:
PUT /your_index/_mapping
{
  "properties": {
    "new_text_field": {
      "type": "text"
    }
  }
}
  1. 修改字段属性:对于一些非核心属性,如 index_optionsstore 等,可以在不重建索引的情况下进行修改。例如,将一个 text 字段的 index_optionsfreqs 修改为 positions
PUT /your_index/_mapping
{
  "properties": {
    "article_title": {
      "type": "text",
      "index_options": "positions"
    }
  }
}

重建索引

  1. 重建索引的场景:当需要更改字段的数据类型、添加复杂类型字段且无法通过部分更新实现时,就需要重建索引。例如,将一个 text 类型字段改为 keyword 类型,或者向索引中添加一个嵌套类型字段。
  2. 重建索引步骤
    • 创建新索引并定义映射:首先创建一个新的索引,并根据需求定义好映射。
PUT /new_index
{
  "mappings": {
    "properties": {
      "field1": {
        "type": "text"
      },
      "new_nested_field": {
        "type": "nested",
        "properties": {
          "sub_field1": {
            "type": "text"
          }
        }
      }
    }
  }
}
  • 使用 _reindex API 迁移数据:使用 _reindex API 将旧索引的数据迁移到新索引。
POST _reindex
{
  "source": {
    "index": "old_index"
  },
  "dest": {
    "index": "new_index"
  }
}
  • 替换索引:迁移完成后,可以通过别名等方式将新索引替换旧索引,确保应用程序能够使用新的索引结构。

通过以上详细的介绍,涵盖了 Elasticsearch 映射属性设置的各个方面,从基础概念到复杂设置,再到映射的更新与管理,希望能帮助开发者全面掌握 Elasticsearch 映射的相关知识,并在实际应用中灵活运用。