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

ElasticSearch映射属性设置的技巧

2023-01-094.2k 阅读

ElasticSearch 映射属性设置的技巧

理解 ElasticSearch 映射

在 ElasticSearch 中,映射(Mapping)就像是数据库表的结构定义,它决定了文档(类似数据库中的行)如何被存储以及其中各个字段(类似数据库中的列)的数据类型和相关属性。映射不仅定义了字段的数据类型,还包含了诸如分词器(analyzer)、是否索引(index)、是否存储(store)等属性的设置,这些设置对于数据的检索、存储和展示都起着关键作用。

例如,当我们创建一个名为 products 的索引来存储商品信息时,我们需要为每个商品字段定义映射。假设商品有 name(名称)、price(价格)、description(描述)等字段,name 可能适合使用文本类型并指定合适的分词器以支持全文搜索,price 则应使用数值类型,description 同样可以是文本类型但可能需要不同的分词策略。

基本数据类型的映射设置

  1. 文本类型(text)
    • 适用场景:用于存储长文本,如文章内容、产品描述等,支持全文搜索。
    • 属性设置
      • analyzer:指定分词器。例如,对于英文文本,standard 分词器是默认的,它会按词进行拆分。如果是中文,可能需要使用 ik_smartik_max_word 等分词器。
      • index:默认为 true,表示该字段会被索引以支持搜索。如果设置为 false,则该字段无法被搜索,但仍会存储在文档中。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "description": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}
  1. 关键字类型(keyword)
    • 适用场景:用于存储短文本,如产品型号、类别名称等,适合精确匹配搜索。
    • 属性设置
      • index:默认为 true,可精确匹配搜索。
      • doc_values:默认为 true,用于排序和聚合操作。如果不需要对该字段进行排序或聚合,可以设置为 false 以节省磁盘空间。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "product_type": {
        "type": "keyword"
      }
    }
  }
}
  1. 数值类型
    • 适用场景:存储数值数据,如价格、数量等。
    • 属性设置
      • coerce:默认为 true,表示如果输入的值与定义的数值类型不完全匹配,ElasticSearch 会尝试进行类型转换。例如,将字符串 "10" 转换为数值 10。如果设置为 false,类型不匹配时会抛出异常。
      • index:默认为 true,支持数值范围搜索和排序。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "price": {
        "type": "float"
      }
    }
  }
}
  1. 日期类型(date)
    • 适用场景:存储日期和时间信息,如产品发布日期、订单创建时间等。
    • 属性设置
      • format:指定日期格式。常见格式有 yyyy - MM - ddyyyy - MM - dd HH:mm:ss 等。如果不指定,默认支持多种日期格式解析。
      • index:默认为 true,支持日期范围搜索。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "release_date": {
        "type": "date",
        "format": "yyyy - MM - dd"
      }
    }
  }
}

复杂数据类型的映射设置

  1. 对象类型(object)
    • 适用场景:当文档中的某个字段本身又是一个结构化的数据集合时使用。例如,一个商品文档中的 manufacturer 字段,它包含 nameaddress 等子字段。
    • 属性设置:对象类型的子字段遵循普通字段的映射规则。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "manufacturer": {
        "type": "object",
        "properties": {
          "name": {
            "type": "text"
          },
          "address": {
            "type": "text"
          }
        }
      }
    }
  }
}
  1. 嵌套类型(nested)
    • 适用场景:与对象类型类似,但嵌套类型可以更好地处理数组中的对象。当数组中的每个对象需要独立进行搜索和聚合时,应使用嵌套类型。例如,一个商品文档中有多个 reviews(评论),每个评论都有 author(作者)、content(内容)和 rating(评分),且需要对每个评论独立搜索。
    • 属性设置
      • index:默认为 true,与普通字段类似。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "reviews": {
        "type": "nested",
        "properties": {
          "author": {
            "type": "text"
          },
          "content": {
            "type": "text"
          },
          "rating": {
            "type": "integer"
          }
        }
      }
    }
  }
}
  1. 地理空间类型(geo - point 和 geo - shape)
    • geo - point 类型
      • 适用场景:存储地理坐标点,如店铺的经纬度位置,用于附近搜索等地理空间查询。
      • 属性设置:可以通过 lat_lon 格式或 geohash 格式存储。lat_lon 格式直接存储纬度和经度,geohash 则是一种将地理坐标编码为字符串的方式。
      • 代码示例
PUT /stores
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}
  • geo - shape 类型
    • 适用场景:存储复杂的地理形状,如城市边界、区域范围等。
    • 属性设置:支持多种几何形状的表示,如多边形(Polygon)、线(LineString)等。
    • 代码示例
PUT /regions
{
  "mappings": {
    "properties": {
      "boundary": {
        "type": "geo_shape"
      }
    }
  }
}

多字段映射

  1. 适用场景 有时候一个字段可能需要以多种方式进行索引和搜索。例如,一个产品名称字段,既需要进行全文搜索,也需要进行精确匹配搜索。
  2. 实现方式 通过在映射中使用 fields 属性来定义同一个字段的不同版本。
  3. 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

在这个例子中,product_name 字段是文本类型用于全文搜索,而 product_name.keyword 字段是关键字类型用于精确匹配搜索。

动态映射与静态映射

  1. 动态映射
    • 原理:当 ElasticSearch 接收到一个新文档时,如果索引中不存在该文档字段的映射,它会根据文档中字段的数据类型自动推断并创建映射,这就是动态映射。
    • 优点:使用方便,对于快速开发和测试环境很友好,无需预先定义所有字段的映射。
    • 缺点:自动推断的映射可能不符合业务需求。例如,对于数字字符串,可能会错误地推断为数值类型,导致一些数据处理问题。
    • 控制动态映射
      • dynamic 属性:在索引映射中,可以通过 dynamic 属性控制动态映射行为。dynamic 有三个取值:true(默认)表示自动添加新字段的映射;false 表示忽略新字段,不添加映射;strict 表示如果遇到新字段,抛出异常。
      • 代码示例
PUT /products
{
  "mappings": {
    "dynamic": "false",
    "properties": {
      "name": {
        "type": "text"
      }
    }
  }
}
  1. 静态映射
    • 原理:在创建索引之前,手动定义好所有字段的映射,这就是静态映射。
    • 优点:可以精确控制每个字段的映射属性,确保数据存储和搜索符合业务需求。
    • 缺点:需要在前期投入更多的时间来设计映射,对于需求变化频繁的场景不够灵活。

映射属性的高级设置

  1. 分词器(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"
      }
    }
  }
}
  1. 文档值(doc_values)
    • 作用:用于排序、聚合和脚本计算。默认情况下,除了 text 类型,其他类型的字段都启用了 doc_values
    • 设置为 false 的情况:如果确定某个字段不会用于排序、聚合等操作,可以将 doc_values 设置为 false 以节省磁盘空间。例如,对于仅用于显示但不参与任何搜索相关计算的字段。
    • 代码示例
PUT /products
{
  "mappings": {
    "properties": {
      "product_code": {
        "type": "keyword",
        "doc_values": false
      }
    }
  }
}

映射的更新与管理

  1. 更新映射
    • 添加新字段:可以直接向现有索引的映射中添加新字段,只要索引的 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 不支持直接删除单个字段的映射,但可以通过重建索引,在新索引映射中不包含该字段来实现。

性能优化与映射属性设置

  1. 合理选择数据类型
    • 避免过度使用文本类型:文本类型由于需要分词等操作,占用的磁盘空间和计算资源相对较多。对于一些不需要全文搜索的短文本字段,应优先使用关键字类型。
    • 精确数值类型:对于数值字段,选择合适的数值类型,如 integer 用于整数,float 用于小数,避免使用过大范围的类型(如 double 用于小范围的浮点数)以节省空间。
  2. 优化分词器使用
    • 减少不必要的分词:对于一些不需要进行复杂分词的字段,如产品型号,使用简单的分词器或关键字类型,避免复杂分词带来的性能开销。
    • 缓存分词结果:在高并发搜索场景下,可以考虑使用 ElasticSearch 的缓存机制来缓存分词结果,减少重复分词的开销。
  3. 控制索引选项和文档值
    • 根据需求设置 index_options:如果不需要词频、位置等详细信息,应选择较低的 index_options 设置,如 docs,以减少磁盘空间占用。
    • 合理设置 doc_values:对于不会用于排序、聚合的字段,关闭 doc_values 可以节省大量磁盘空间,尤其是在字段值较多的情况下。

通过合理设置 ElasticSearch 的映射属性,可以优化数据存储、提高搜索性能,并更好地满足业务需求。在实际应用中,需要根据具体的数据特点和业务场景,灵活运用这些映射属性设置技巧。