ElasticSearch映射属性设置的技巧
2023-01-094.2k 阅读
ElasticSearch 映射属性设置的技巧
理解 ElasticSearch 映射
在 ElasticSearch 中,映射(Mapping)就像是数据库表的结构定义,它决定了文档(类似数据库中的行)如何被存储以及其中各个字段(类似数据库中的列)的数据类型和相关属性。映射不仅定义了字段的数据类型,还包含了诸如分词器(analyzer)、是否索引(index)、是否存储(store)等属性的设置,这些设置对于数据的检索、存储和展示都起着关键作用。
例如,当我们创建一个名为 products
的索引来存储商品信息时,我们需要为每个商品字段定义映射。假设商品有 name
(名称)、price
(价格)、description
(描述)等字段,name
可能适合使用文本类型并指定合适的分词器以支持全文搜索,price
则应使用数值类型,description
同样可以是文本类型但可能需要不同的分词策略。
基本数据类型的映射设置
- 文本类型(text)
- 适用场景:用于存储长文本,如文章内容、产品描述等,支持全文搜索。
- 属性设置:
- analyzer:指定分词器。例如,对于英文文本,
standard
分词器是默认的,它会按词进行拆分。如果是中文,可能需要使用ik_smart
或ik_max_word
等分词器。 - index:默认为
true
,表示该字段会被索引以支持搜索。如果设置为false
,则该字段无法被搜索,但仍会存储在文档中。
- analyzer:指定分词器。例如,对于英文文本,
- 代码示例:
PUT /products
{
"mappings": {
"properties": {
"description": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
- 关键字类型(keyword)
- 适用场景:用于存储短文本,如产品型号、类别名称等,适合精确匹配搜索。
- 属性设置:
- index:默认为
true
,可精确匹配搜索。 - doc_values:默认为
true
,用于排序和聚合操作。如果不需要对该字段进行排序或聚合,可以设置为false
以节省磁盘空间。
- index:默认为
- 代码示例:
PUT /products
{
"mappings": {
"properties": {
"product_type": {
"type": "keyword"
}
}
}
}
- 数值类型
- 适用场景:存储数值数据,如价格、数量等。
- 属性设置:
- coerce:默认为
true
,表示如果输入的值与定义的数值类型不完全匹配,ElasticSearch 会尝试进行类型转换。例如,将字符串"10"
转换为数值 10。如果设置为false
,类型不匹配时会抛出异常。 - index:默认为
true
,支持数值范围搜索和排序。
- coerce:默认为
- 代码示例:
PUT /products
{
"mappings": {
"properties": {
"price": {
"type": "float"
}
}
}
}
- 日期类型(date)
- 适用场景:存储日期和时间信息,如产品发布日期、订单创建时间等。
- 属性设置:
- format:指定日期格式。常见格式有
yyyy - MM - dd
、yyyy - MM - dd HH:mm:ss
等。如果不指定,默认支持多种日期格式解析。 - index:默认为
true
,支持日期范围搜索。
- format:指定日期格式。常见格式有
- 代码示例:
PUT /products
{
"mappings": {
"properties": {
"release_date": {
"type": "date",
"format": "yyyy - MM - dd"
}
}
}
}
复杂数据类型的映射设置
- 对象类型(object)
- 适用场景:当文档中的某个字段本身又是一个结构化的数据集合时使用。例如,一个商品文档中的
manufacturer
字段,它包含name
、address
等子字段。 - 属性设置:对象类型的子字段遵循普通字段的映射规则。
- 代码示例:
- 适用场景:当文档中的某个字段本身又是一个结构化的数据集合时使用。例如,一个商品文档中的
PUT /products
{
"mappings": {
"properties": {
"manufacturer": {
"type": "object",
"properties": {
"name": {
"type": "text"
},
"address": {
"type": "text"
}
}
}
}
}
}
- 嵌套类型(nested)
- 适用场景:与对象类型类似,但嵌套类型可以更好地处理数组中的对象。当数组中的每个对象需要独立进行搜索和聚合时,应使用嵌套类型。例如,一个商品文档中有多个
reviews
(评论),每个评论都有author
(作者)、content
(内容)和rating
(评分),且需要对每个评论独立搜索。 - 属性设置:
- index:默认为
true
,与普通字段类似。
- index:默认为
- 代码示例:
- 适用场景:与对象类型类似,但嵌套类型可以更好地处理数组中的对象。当数组中的每个对象需要独立进行搜索和聚合时,应使用嵌套类型。例如,一个商品文档中有多个
PUT /products
{
"mappings": {
"properties": {
"reviews": {
"type": "nested",
"properties": {
"author": {
"type": "text"
},
"content": {
"type": "text"
},
"rating": {
"type": "integer"
}
}
}
}
}
}
- 地理空间类型(geo - point 和 geo - shape)
- geo - point 类型
- 适用场景:存储地理坐标点,如店铺的经纬度位置,用于附近搜索等地理空间查询。
- 属性设置:可以通过
lat_lon
格式或geohash
格式存储。lat_lon
格式直接存储纬度和经度,geohash
则是一种将地理坐标编码为字符串的方式。 - 代码示例:
- geo - point 类型
PUT /stores
{
"mappings": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
- geo - shape 类型
- 适用场景:存储复杂的地理形状,如城市边界、区域范围等。
- 属性设置:支持多种几何形状的表示,如多边形(Polygon)、线(LineString)等。
- 代码示例:
PUT /regions
{
"mappings": {
"properties": {
"boundary": {
"type": "geo_shape"
}
}
}
}
多字段映射
- 适用场景 有时候一个字段可能需要以多种方式进行索引和搜索。例如,一个产品名称字段,既需要进行全文搜索,也需要进行精确匹配搜索。
- 实现方式
通过在映射中使用
fields
属性来定义同一个字段的不同版本。 - 代码示例
PUT /products
{
"mappings": {
"properties": {
"product_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
在这个例子中,product_name
字段是文本类型用于全文搜索,而 product_name.keyword
字段是关键字类型用于精确匹配搜索。
动态映射与静态映射
- 动态映射
- 原理:当 ElasticSearch 接收到一个新文档时,如果索引中不存在该文档字段的映射,它会根据文档中字段的数据类型自动推断并创建映射,这就是动态映射。
- 优点:使用方便,对于快速开发和测试环境很友好,无需预先定义所有字段的映射。
- 缺点:自动推断的映射可能不符合业务需求。例如,对于数字字符串,可能会错误地推断为数值类型,导致一些数据处理问题。
- 控制动态映射:
- dynamic 属性:在索引映射中,可以通过
dynamic
属性控制动态映射行为。dynamic
有三个取值:true
(默认)表示自动添加新字段的映射;false
表示忽略新字段,不添加映射;strict
表示如果遇到新字段,抛出异常。 - 代码示例:
- dynamic 属性:在索引映射中,可以通过
PUT /products
{
"mappings": {
"dynamic": "false",
"properties": {
"name": {
"type": "text"
}
}
}
}
- 静态映射
- 原理:在创建索引之前,手动定义好所有字段的映射,这就是静态映射。
- 优点:可以精确控制每个字段的映射属性,确保数据存储和搜索符合业务需求。
- 缺点:需要在前期投入更多的时间来设计映射,对于需求变化频繁的场景不够灵活。
映射属性的高级设置
- 分词器(analyzer)的深入设置
- 自定义分词器:除了使用内置分词器,还可以自定义分词器以满足特定业务需求。例如,对于一些专业领域的术语,可能需要特殊的分词规则。
- 代码示例:
PUT /custom_index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"stop"
]
}
}
}
},
"mappings": {
"properties": {
"text_field": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
在这个例子中,自定义了一个 my_analyzer
分词器,它基于 standard
分词器,并添加了 lowercase
(转换为小写)和 stop
(去除停用词)过滤器。
2. 索引选项(index_options)
- 作用:控制字段索引的详细程度,影响搜索性能和磁盘空间占用。
- 取值:
- docs:只索引文档号,适合不需要词项统计和位置信息的场景,占用空间最小。
- freqs:索引文档号和词频,适合需要词频信息的场景。
- positions:索引文档号、词频和位置信息,适合短语搜索等需要位置信息的场景。
- offsets:索引文档号、词频、位置和偏移量信息,适合高亮显示等需要字符偏移量信息的场景,占用空间最大。
- 代码示例:
PUT /documents
{
"mappings": {
"properties": {
"content": {
"type": "text",
"index_options": "freqs"
}
}
}
}
- 文档值(doc_values)
- 作用:用于排序、聚合和脚本计算。默认情况下,除了
text
类型,其他类型的字段都启用了doc_values
。 - 设置为 false 的情况:如果确定某个字段不会用于排序、聚合等操作,可以将
doc_values
设置为false
以节省磁盘空间。例如,对于仅用于显示但不参与任何搜索相关计算的字段。 - 代码示例:
- 作用:用于排序、聚合和脚本计算。默认情况下,除了
PUT /products
{
"mappings": {
"properties": {
"product_code": {
"type": "keyword",
"doc_values": false
}
}
}
}
映射的更新与管理
- 更新映射
- 添加新字段:可以直接向现有索引的映射中添加新字段,只要索引的
dynamic
属性允许(默认为允许)。 - 代码示例:
- 添加新字段:可以直接向现有索引的映射中添加新字段,只要索引的
PUT /products/_mapping
{
"properties": {
"new_field": {
"type": "text"
}
}
}
- 修改现有字段:不能直接修改现有字段的类型和一些重要属性,因为这可能会导致数据丢失或搜索功能异常。如果需要修改,通常需要使用 reindex API 来重建索引。
- 代码示例:
POST _reindex
{
"source": {
"index": "old_products"
},
"dest": {
"index": "new_products"
}
}
在重建索引过程中,可以在新索引的映射中修改字段属性。 2. 删除映射
- 删除整个索引:可以使用 DELETE 请求删除整个索引,包括其映射和所有文档数据。
- 代码示例:
DELETE /products
- 删除单个字段:目前 ElasticSearch 不支持直接删除单个字段的映射,但可以通过重建索引,在新索引映射中不包含该字段来实现。
性能优化与映射属性设置
- 合理选择数据类型
- 避免过度使用文本类型:文本类型由于需要分词等操作,占用的磁盘空间和计算资源相对较多。对于一些不需要全文搜索的短文本字段,应优先使用关键字类型。
- 精确数值类型:对于数值字段,选择合适的数值类型,如
integer
用于整数,float
用于小数,避免使用过大范围的类型(如double
用于小范围的浮点数)以节省空间。
- 优化分词器使用
- 减少不必要的分词:对于一些不需要进行复杂分词的字段,如产品型号,使用简单的分词器或关键字类型,避免复杂分词带来的性能开销。
- 缓存分词结果:在高并发搜索场景下,可以考虑使用 ElasticSearch 的缓存机制来缓存分词结果,减少重复分词的开销。
- 控制索引选项和文档值
- 根据需求设置 index_options:如果不需要词频、位置等详细信息,应选择较低的
index_options
设置,如docs
,以减少磁盘空间占用。 - 合理设置 doc_values:对于不会用于排序、聚合的字段,关闭
doc_values
可以节省大量磁盘空间,尤其是在字段值较多的情况下。
- 根据需求设置 index_options:如果不需要词频、位置等详细信息,应选择较低的
通过合理设置 ElasticSearch 的映射属性,可以优化数据存储、提高搜索性能,并更好地满足业务需求。在实际应用中,需要根据具体的数据特点和业务场景,灵活运用这些映射属性设置技巧。