Elasticsearch mapping 之 性能相关配置

ES 常见类型

通用类型:

二进制: binary

布尔型: boolean

字符串: keyword, constant_keyword, wildcard, text

别名: alias

对象: object, flattened, nested, join

结构化数据类型: Range, ip, version, murmur3

空间数据类型: geo_point, geo_shape, point, shape

性能相关参数

_all

_all 字段的索引方式是将所有其他字段的值作为一个大字符串索引的,通过include_in_all参数指定哪些字段的内容放入_all 字段,_all 字段在v6.0+已经废弃,v7.0正式移除,但是可以通过copy_to来实现_all相同功能.

python 复制代码
PUT /test_index
{
  "mappings": {
    "properties": {
      "field1": {
        "type": "text",
        "copy_to": "field_all"
      },
      "field2": {
        "type": "text",
        "copy_to": "field_all"
      },
      "field_all": {
        "type": "text"
      }
    }
  }
}

POST /test_index/_doc/1
{
  "field1": "smith",
  "field2": "John@example.com"
}

GET /test_index/_search
{
  "query": {
    "match": {
      "field_all": "smith"
    }
  }
}

现在field_all存的是["smith", "John@example.com"].

优点: 当我们想要查询field1或者field2中包含"smith"的时候,只要查询field_all字段就行. 不需要从两个字段的倒排索引中查询两遍.

**缺点:**我们不清楚"smith"是在field1还是field2, 需要按照字段或者"smith"在字段中的占比算score的时候就不支持了. 额外需要硬盘空间存储field_all字段内容.

_source

_source 字段用于存储 post 到 ES 的原始 json 文档。为什么要存储原始文档呢?因为 ES 采用倒排索引对文本进行搜索,而倒排索引无法存储原始输入文本。一段文本交给ES后,首先会被分析器(analyzer)打散成单词,为了保证搜索的准确性,在打散的过程中,会去除文本中的标点符号,统一文本的大小写,甚至对于英文等主流语言,会把发生形式变化的单词恢复成原型或词根,然后再根据统一规整之后的单词建立倒排索引,经过如此一番处理,原文已经面目全非。因此需要有一个地方来存储原始的信息,以便在搜到这个文档时能够把原文返回给查询者。和所有被存储的字段一样, _source 字段在被写入磁盘之前先会被压缩。

那么一定要存储原始文档吗?不一定!如果没有取出整个原始 json 结构体的需求,可以在 mapping 中关闭 source 字段或者只在 source 中存储部分字段(使用store)。但是这样做有些负面影响:

(1)不能获取到原文

(2)无法reindex:如果存储了 source,当 index 发生损坏,或需要改变 mapping 结构时,由于存在原始数据,ES可以通过原始数据自动重建index,如果不存 source 则无法实现

(3)无法在查询中使用script:因为 script 需要访问 source 中的字段

(4)如果没有 _source 字段,部分 update 请求不会生效。

如果不需要如上功能,可以禁用_source,减少空间或者指定字段储存到_source, 一般不建议禁用_source,可以通过设置best_compression高压缩比来代替禁用_source.

python 复制代码
PUT test_index
{
  "mappings": {
    "_source": {
      "enabled": false
    }
  }
}

PUT /test_index
{
  "mappings": {
    "_source": {
      "includes": [
        "field1"
      ],
      "excludes": [
        "field2"
      ]
    }
  }
}

store

store 决定一个字段是否要被单独存储。大家可能会有疑问,_source 里面不是已经存储了原始的文档嘛,为什么还需要一个额外的 store 属性呢?原因如下:

(1)如果禁用了 _source 保存,可以通过指定 store 属性来单独保存某个或某几个字段,而不是将整个输入文档保存到 _source 中。

(2)如果 _source 中有长度很长的文本(如一篇文章)和较短的文本(如文章标题),当只需要取出标题时,如果使用 _source 字段,ES需要读取整个 _source 字段,然后返回其中的 title,由此会引来额外的IO开销,降低效率。此时可以选择将 title 的 store 设置为true,在 _source 字段外单独存储一份。读取时不必在读取整 _source 字段了。但是需要注意,应该避免使用 store 查询多个字段,因为 store 的存储在磁盘上不连续,ES在读取不同的 store 字段时,每个字段的读取均需要在磁盘上进行查询操作,而使用 _source 字段可以一次性连续读取多个字段。

python 复制代码
PUT /test_index
{
  "mappings": {
    "properties": {
      "field1": {
        "type": "text",
        "copy_to": "field_all",
        "store": true
      },
      "field2": {
        "type": "text",
        "copy_to": "field_all"
      },
      "field_all": {
        "type": "text",
        "store": true
      }
    },
    "_source": {
      "enabled": false
    }
  }
}

GET /test_index/_search
{
  "stored_fields": ["field1", "field_all"]
}

doc_values

倒排索引可以提供全文检索能力,但是无法提供对排序和数据聚合的支持。如果没有doc_values, 聚合A字段流程如下:

  1. 通过倒排索引查询到匹配的docId列表
  2. 根据docId列表去各个分片获取到Doc的_source字段
  3. 解压缩_source字段获取json字符串里面的A字段
  4. 统一在内存中进行A字段的聚合

doc_values 本质上是一个序列化的列式存储结构,适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。当A字段开启doc_values时, 聚合A字段流程如下:

  1. 通过倒排索引查询到匹配的docId列表
  2. 根据docId列表去各个分片获取到Doc的doc_values里面的A字段, 由于doc_values是列存储,A字段在内存中是连续的,获取方便
  3. 统一在内存中进行A字段的聚合

默认情况下,ES几乎会为所有类型的字段存储doc_value,但是 text 或 text_annotated 等可分词字段不支持 doc values 。如果不需要对某个字段进行排序或者聚合,则可以关闭该字段的doc_value存储***(doc_values: false)**,关闭后不能进行聚合和排序操作*。

python 复制代码
PUT /test_index
{
  "mappings": {
    "properties": {
      "field1": {
        "type": "keyword",
        "copy_to": "field_all",
        "store": true
      },
      "field2": {
        "type": "keyword",
        "copy_to": "field_all",
        "doc_values": false
      },
      "field_all": {
        "type": "text",
        "store": true
      }
    },
    "_source": {
      "enabled": false
    }
  }
}

GET /test_index/_search
{
  "query": {
      "match_all": {}
  },
  "aggregations": {
    "terms_field2": {
      "terms": {
        "field": "field1"
      }
    }
  }
}

index

控制倒排索引,用于标识指定字段是否需要被索引。默认情况下是开启的,如果关闭了 index,则该字段的内容不会被 analyze 分词,也不会存入倒排索引,即意味着该字段无法被搜索。

python 复制代码
PUT /test_index
{
  "mappings": {
    "properties": {
      "field1": {
        "type": "keyword",
        "copy_to": "field_all",
        "store": true,
        "index": false
      },
      "field2": {
        "type": "keyword",
        "copy_to": "field_all",
        "doc_values": false
      },
      "field_all": {
        "type": "text",
        "store": true
      }
    },
    "_source": {
      "enabled": true
    }
  }
}

GET /test_index/_search
{
  "query": {
    "match": {
      "field1": "smith"
    }
  }
}

enabled

这是一个 index 和 doc_value 的总开关,如果 enabled 设置为false,则这个字段将会仅存在于 source 中,其对应的 index 和 doc_value 都不会被创建。这意味着,该字段将不可以被搜索、排序或者聚合,但可以通过 source 获取其原始值。

相关推荐
青云交5 分钟前
大数据新视界 -- Hive 查询性能优化:基于成本模型的奥秘(上)(5/ 30)
大数据·优化器·执行计划·统计信息·hive 查询性能·成本模型·hive 优化
gma9999 分钟前
【BUG】ES使用过程中问题解决汇总
大数据·elasticsearch·搜索引擎
Mephisto.java1 小时前
【大数据学习 | Spark-Core】RDD的缓存(cache and checkpoint)
大数据·学习·spark
zmd-zk1 小时前
flink学习(3)——方法的使用—对流的处理(map,flatMap,filter)
java·大数据·开发语言·学习·flink·tensorflow
NiNg_1_2341 小时前
Hadoop的MapReduce详解
大数据·hadoop·mapreduce
在下不上天1 小时前
flume-将日志采集到hdfs
大数据·linux·运维·hadoop·hdfs·flume
zmd-zk1 小时前
flink学习(1)——standalone模式的安装
大数据·hadoop·flink·实时
Dreams°1231 小时前
【大数据测试Flume:从 0-1详细教程】
大数据·python·单元测试·自动化·flume
vvw&2 小时前
如何在 Ubuntu 22.04 上安装带有 Nginx 的 ELK Stack
linux·运维·nginx·ubuntu·elk·elasticsearch·开源项目
开利网络3 小时前
数字化转型:企业降本增效的关键之路
大数据·物联网·搜索引擎·信息可视化·1024程序员节