这是ElasticSearch 2.4 版本系列的第八篇:html
在ElasticSearch 2.4版本中,文档存储的介质分为内存和硬盘:内存速度快,可是容量有限;硬盘速度较慢,可是容量很大。同时,ElasticSearch进程自身的运行也须要内存空间,必须保证ElasticSearch进程有充足的运行时内存。为了使ElasticSearch引擎达到最佳性能,必须合理分配有限的内存和硬盘资源。正则表达式
一,倒排索引(Inverted Index)bootstrap
ElasticSearch引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,倒排索引创建的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。数组
举个例子,文档和词条之间的关系以下图:网络
字段值被分析以后,存储在倒排索引中,倒排索引存储的是分词(Term)和文档(Doc)之间的关系,简化版的倒排索引以下图:session
从图中能够看出,倒排索引有一个词条的列表,每一个分词在列表中是惟一的,记录着词条出现的次数,以及包含词条的文档。实际上,ElasticSearch引擎建立的倒排索引比这个复杂得多。数据结构
1,段是倒排索引的组成部分app
倒排索引是由段(Segment)组成的,段存储在硬盘(Disk)文件中。索引段不是实时更新的,这意味着,段在写入硬盘以后,就再也不被更新。在删除文档时,ElasticSearch引擎把已删除的文档的信息存储在一个单独的文件中,在搜索数据时,ElasticSearch引擎首先从段中执行查询,再从查询结果中过滤被删除的文档,这意味着,段中存储着被删除的文档,这使得段中含有”正常文档“的密度下降。多个段能够经过段合并(Segment Merge)操做把“已删除”的文档将从段中物理删除,把未删除的文档合并到一个新段中,新段中没有”已删除文档“,所以,段合并操做可以提升索引的查找速度,可是,段合并是IO密集型操做,须要消耗大量的硬盘IO。elasticsearch
在ElasticSearch中,大多数查询都须要从硬盘文件(索引的段数据存储在硬盘文件中)中获取数据,所以,在全局配置文件elasticsearch.yml 中,把结点的路径(Path)配置为性能较高的硬盘,可以提升查询性能。默认状况下,ElasticSearch使用基于安装目录的相对路径来配置结点的路径,安装目录由属性path.home显示,在home path下,ElasticSearch自动建立config,data,logs和plugins目录,通常状况下不须要对结点路径单独配置。结点的文件路径配置项:ide
2,分词和原始文本的存储
映射参数index决定ElasticSearch引擎是否对文本字段执行分析操做,也就是说分析操做把文本分割成一个一个的分词,也就是标记流(Token Stream),把分词编入索引,使分词可以被搜索到:
字段的原始值是否被存储到倒排索引,是由映射参数store决定的,默认值是false,也就是,原始值不存储到倒排索引中。
映射参数index和store的区别在于:
3,单个分词的最大长度
若是设置字段的index属性为not_analyzed,原始文本将做为单个分词,其最大长度跟UTF8 编码有关,默认的最大长度是32766Bytes,若是字段的文本超过该限制,那么ElasticSearch将跳过(Skip)该文档,并在Response中抛出异常消息:
operation[607]: index returned 400 _index: ebrite _type: events _id: 76860 _version: 0 error: Type: illegal_argument_exception Reason: "Document contains at least one immense term in field="event_raw" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[112, 114,... 115]...', original message: bytes can be at most 32766 in length; got 35100" CausedBy:Type: max_bytes_length_exceeded_exception Reason: "bytes can be at most 32766 in length; got 35100"
能够在字段中设置ignore_above属性,该属性值指的是字符数量,而不是字节数量;因为一个UTF8字符最多占用3个字节,所以,能够设置
“ignore_above”:10000
这样,超过30000字节以后的字符将会被分析器忽略,单个分词(Term)的最大长度是30000Bytes。
The value for
ignore_above
is the character count, but Lucene counts bytes. If you use UTF-8 text with many non-ASCII characters, you may want to set the limit to32766 / 3 = 10922
since UTF-8 characters may occupy at most 3 bytes.
二,列式存储(doc_values)
默认状况下,大多数字段被索引以后,可以被搜索到。倒排索引是由一个有序的词条列表构成的,每个词条在列表中都是惟一存在的,经过这种数据存储模式,你能够很快查找到包含某一个词条的文档列表。可是,排序和聚合操做采用相反的数据访问模式,这两种操做不是查找词条以发现文档,而是查找文档,以发现字段中包含的词条。ElasticSearch使用列式存储实现排序和聚合查询。
文档值(doc_values)是存储在硬盘上的数据结构,在索引时(index time)根据文档的原始值建立,文档值是一个列式存储风格的数据结构,很是适合执行存储和聚合操做,除了字符类型的分析字段以外,其余字段类型都支持文档值存储。默认状况下,字段的文档值存储是启用的,除了字符类型的分析字段以外。若是不须要对字段执行排序或聚合操做,能够禁用字段的文档值,以节省硬盘空间。
"mappings": { "my_type": { "properties": { "status_code": { "type": "string", "index": "not_analyzed" }, "session_id": { "type": "string", "index": "not_analyzed", "doc_values": false } } } }
三,顺排索引(fielddata)
字符类型的分析字段,不支持文档值(doc_values),可是,支持fielddata数据结构,fielddata数据结构存储在JVM的堆内存中。相比文档值(数据存储在硬盘上),fielddata字段(数据存储在内存中)的查询性能更高。默认状况下,ElasticSearch引擎在第一次对字段执行聚合或排序查询时((query-time)),建立fielddata数据结构;在后续的查询请求中,ElasticSearch引擎使用fielddata数据结构以提升聚合和排序的查询性能。
在ElasticSearch中,倒排索引的各个段(segment)的数据存储在硬盘文件上,从整个倒排索引的段中读取字段数据以后,ElasticSearch引擎首先反转词条和文档之间的关系,建立文档和词条之间的关系,即建立顺排索引,而后把顺排索引存储在JVM的堆内存中。把倒排索引加载到fielddata结构是一个很是消耗硬盘IO资源的过程,所以,数据一旦被加载到内存,最好保持在内存中,直到索引段(segment)的生命周期结束。默认状况下,倒排索引的每一个段(segment),都会建立相应的fielddata结构,以存储字符类型的分析字段值,可是,须要注意的是,分配的JVM堆内存是有限的,Fileddata把数据存储在内存中,会占用过多的JVM堆内存,甚至耗尽JVM赖以正常运行的内存空间,反而会下降ElasticSearch引擎的查询性能。
1,format属性
fielddata会消耗大量的JVM内存,所以,尽可能为JVM设置大的内存,不要为没必要要的字段启用fielddata存储。经过format参数控制是否启用字段的fielddata特性,字符类型的分析字段,fielddata的默认值是paged_bytes,这就意味着,默认状况下,字符类型的分析字段启用fielddata存储。一旦禁用fielddata存储,那么字符类型的分析字段将再也不支持排序和聚合查询。
"mappings": { "my_type": { "properties": { "text": { "type": "string", "fielddata": { "format": "disabled" } } } } }
2,加载属性(loading)
loading属性控制fielddata加载到内存的时机,可能的值是lazy,eager和eager_global_ordinals,默认值是lazy。
四,JVM进程使用的内存和堆内存
1,配置ElasticSearch使用的内存
ElasticSearch使用JAVA_OPTS环境变量(Environment Variable)启动JVM进程,在JAVA_OPTS中,最重要的配置是:-Xmx参数控制分配给JVM进程的最大内存,-Xms参数控制分配给JVM进程的最小内存。一般状况下,使用默认的配置就能知足工程须要。
ES_HEAP_SIZE 环境变量控制分配给JVM进程的堆内存(Heap Memory)大小,顺排索引(fielddata)的数据存储在堆内存(Heap Memory)中。
2,内存锁定
大多数应用程序尝试使用尽量多的内存,并尽量把未使用的内存换出,可是,内存换出会影响ElasticSearch引擎的查询性能,推荐启用内存锁定,禁用ElasticSearch内存的换进换出。
在全局配置文档 elasticsearch.yml中,设置 bootstrap.memory_lock为ture,这将锁定ElasticSearch进程的内存地址空间,阻止ElasticSearch内存被OS换出(Swap out)。
参考文档:
Elasticsearch Reference [2.4] » Mapping » Mapping parameters