Elasticsearch中有几个关键属性容易混淆,很多人搞不清楚_source字段里存储的是什么?store属性的true或false和_source字段有什么关系?store属性设置为true和_all有什么关系?index属性又起到什么作用?什么时候设置store属性为true?什么时候应该开启_all字段?本文通过图解的方式,深入理解Elasticsearch中的_source、_all、store和index属性。

图1 Elasticsearch中的_source、_all、store和index属性解析

图1所示, 第二象限是一份原始文档,有title和content2个字段,字段取值分别为”我是中国人”和” 热爱xx党”,这一点没什么可解释的。我们把原始文档写入Elasticsearch,默认情况下,Elasticsearch里面有2份内容,一份是原始文档,也就是_source字段里的内容,我们在Elasticsearch中搜索文档,查看的文档内容就是_source中的内容,如图2,相信大家一定非常熟悉这个界面。

图2 _source字段举例

另一份是倒排索引,倒排索引中的数据结构是倒排记录表,记录了词项和文档之间的对应关系,比如关键词”中国人”包含在文档ID为1的文档中,倒排记录表中存储的就是这种对应关系,当然也包括词频等更多信息。Elasticsearch底层用的是Lucene的API,Elasticsearch之所以能完成全文搜索的功能就是因为存储的有倒排索引。如果把倒排索引拿掉,Elasticsearch是不是和mongoDB很像?

那么文档索引到Elasticsearch的时候,默认情况下是对所有字段创建倒排索引的(动态mapping解析出来为数字类型、布尔类型的字段除外),某个字段是否生成倒排索引是由字段的index属性控制的,在Elasticsearch 5之前,index属性的取值有三个:

  1. analyzed:字段被索引,会做分词,可搜索。反过来,如果需要根据某个字段进搜索,index属性就应该设置为analyzed。
  2. not_analyzed:字段值不分词,会被原样写入索引。反过来,如果某些字段需要完全匹配,比如人名、地名,index属性设置为not_analyzed为佳。
  3. no:字段不写入索引,当然也就不能搜索。反过来,有些业务要求某些字段不能被搜索,那么index属性设置为no即可。

再说_all字段,顾名思义,_all字段里面包含了一个文档里面的所有信息,是一个超级字段。以图中的文档为例,如果开启_all字段,那么title+content会组成一个超级字段,这个字段包含了其他字段的所有内容,当然也可以设置只存储某几个字段到_all属性里面或者排除某些字段。

回到图一的第一象限,用户输入关键词" 中国人",分词以后,Elasticsearch从倒排记录表中查找哪些文档包含词项"中国人 ",注意变化,分词之前" 中国人"是用户查询(query),分词之后在倒排索引中" 中国人"是词项(term)。Elasticsearch根据文档ID(通常是文档ID的集合)返回文档内容给用户,如图一第四象限所示。

通常情况下,对于用户查询的关键字要做高亮处理,如图3所示: 

图3 搜索引擎中的关键字高亮

关键字高亮实质上是根据倒排记录中的词项偏移位置,找到关键词,加上前端的高亮代码。这里就要说到store属性,store属性用于指定是否将原始字段写入索引,默认取值为no。如果在Lucene中,高亮功能和store属性是否存储息息相关,因为需要根据偏移位置到原始文档中找到关键字才能加上高亮的片段。在Elasticsearch,因为_source中已经存储了一份原始文档,可以根据_source中的原始文档实现高亮,在索引中再存储原始文档就多余了,所以Elasticsearch默认是把store属性设置为no。

注意:如果想要对某个字段实现高亮功能,_source和store至少保留一个。下面会给出测试代码。

至此,文章开头提出的几个问题都给出了答案。下面给出这几个字段常用配置的代码。

一、_source配置

_source字段默认是存储的, 什么情况下不用保留_source字段?如果某个字段内容非常多,业务里面只需要能对该字段进行搜索,最后返回文档id,查看文档内容会再次到mysql或者hbase中取数据,把大字段的内容存在Elasticsearch中只会增大索引,这一点文档数量越大结果越明显,如果一条文档节省几KB,放大到亿万级的量结果也是非常可观的。 
如果想要关闭_source字段,在mapping中的设置如下:

  1. {
  2. "yourtype":{
  3. "_source":{
  4. "enabled":false
  5. },
  6. "properties": {
  7. ...
  8. }
  9. }
  10. }

如果只想存储某几个字段的原始值到Elasticsearch,可以通过incudes参数来设置,在mapping中的设置如下:

  1. {
  2. "yourtype":{
  3. "_source":{
  4. "includes":["field1","field2"]
  5. },
  6. "properties": {
  7. ...
  8. }
  9. }
  10. }

同样,可以通过excludes参数排除某些字段:

  1. {
  2. "yourtype":{
  3. "_source":{
  4. "excludes":["field1","field2"]
  5. },
  6. "properties": {
  7. ...
  8. }
  9. }
  10. }

测试,首先创建一个索引

  1. PUT test

设置mapping,禁用_source:

  1. PUT test/test/_mapping
  2. {
  3. "test": {
  4. "_source": {
  5. "enabled": false
  6. }
  7. }
  8. }

写入一条文档:

  1. POST test/test/1
  2. {
  3. "title":"我是中国人",
  4. "content":"热爱xx党"
  5. }

搜索关键词”中国人”:

  1. GET test/_search
  2. {
  3. "query": {
  4. "match": {
  5. "title": "中国人"
  6. }
  7. }
  8. }
  9. {
  10. "took": 9,
  11. "timed_out": false,
  12. "_shards": {
  13. "total": 5,
  14. "successful": 5,
  15. "failed": 0
  16. },
  17. "hits": {
  18. "total": 1,
  19. "max_score": 0.30685282,
  20. "hits": [
  21. {
  22. "_index": "test",
  23. "_type": "test",
  24. "_id": "1",
  25. "_score": 0.30685282
  26. }
  27. ]
  28. }
  29. }

从返回结果中可以看到,搜到了一条文档,但是禁用_source以后查询结果中不会再返回文档原始内容。(注,测试基于ELasticsearch 2.3.3,配置文件中已默认指定ik分词。)

二、_all配置

_all字段默认是关闭的,如果要开启_all字段,索引增大是不言而喻的。_all字段开启适用于不指定搜索某一个字段,根据关键词,搜索整个文档内容。 
开启_all字段的方法和_source类似,mapping中的配置如下:

  1. {
  2. "yourtype": {
  3. "_all": {
  4. "enabled": true
  5. },
  6. "properties": {
  7. ...
  8. }
  9. }
  10. }

也可以通过在字段中指定某个字段是否包含在_all中:

  1. {
  2. "yourtype": {
  3. "properties": {
  4. "field1": {
  5. "type": "string",
  6. "include_in_all": false
  7. },
  8. "field2": {
  9. "type": "string",
  10. "include_in_all": true
  11. }
  12. }
  13. }
  14. }

如果要把字段原始值保存,要设置store属性为true,这样索引会更大,需要根据需求使用。下面给出测试代码。 
创建test索引:

  1. DELETE test
  2. PUT test

设置mapping,这里设置所有字段都保存在_all中并且存储原始值:

  1. PUT test/test/_mapping
  2. {
  3. "test": {
  4. "_all": {
  5. "enabled": true,
  6. "store": true
  7. }
  8. }
  9. }

插入文档:

  1. POST test/test/1
  2. {
  3. "title":"我是中国人",
  4. "content":"热爱xx党"
  5. }

对_all字段进行搜索并高亮:

  1. POST test/_search
  2. {
  3. "fields": ["_all"],
  4. "query": {
  5. "match": {
  6. "_all": "中国人"
  7. }
  8. },
  9. "highlight": {
  10. "fields": {
  11. "_all": {}
  12. }
  13. }
  14. }
  15. {
  16. "took": 3,
  17. "timed_out": false,
  18. "_shards": {
  19. "total": 5,
  20. "successful": 5,
  21. "failed": 0
  22. },
  23. "hits": {
  24. "total": 1,
  25. "max_score": 0.15342641,
  26. "hits": [
  27. {
  28. "_index": "test",
  29. "_type": "test",
  30. "_id": "1",
  31. "_score": 0.15342641,
  32. "_all": "我是中国人 热爱xx党 ",
  33. "highlight": {
  34. "_all": [
  35. "我是<em>中国人</em> 热爱xx党 "
  36. ]
  37. }
  38. }
  39. ]
  40. }
  41. }

Elasticsearch中的query_string和simple_query_string默认就是查询_all字段,示例如下:

  1. GET test/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "xx党"
  6. }
  7. }
  8. }

三、index和score配置

index和store属性实在字段内进行设置的,下面给出一个例子,设置test索引不保存_source,title字段索引但不分析,字段原始值写入索引,content字段为默认属性,代码如下:

  1. DELETE test
  2. PUT test
  3. PUT test/test/_mapping
  4. {
  5. "test": {
  6. "_source": {
  7. "enabled": false
  8. },
  9. "properties": {
  10. "title": {
  11. "type": "string",
  12. "index": "not_analyzed",
  13. "store": "true"
  14. },
  15. "content": {
  16. "type": "string"
  17. }
  18. }
  19. }
  20. }

对title字段进行搜索并高亮,代码如下:

  1. GET test/_search
  2. {
  3. "query": {
  4. "match": {
  5. "title": "我是中国人"
  6. }
  7. },
  8. "highlight": {
  9. "fields": {
  10. "title": {}
  11. }
  12. }
  13. }
  14. {
  15. "took": 6,
  16. "timed_out": false,
  17. "_shards": {
  18. "total": 5,
  19. "successful": 5,
  20. "failed": 0
  21. },
  22. "hits": {
  23. "total": 1,
  24. "max_score": 0.30685282,
  25. "hits": [
  26. {
  27. "_index": "test",
  28. "_type": "test",
  29. "_id": "1",
  30. "_score": 0.30685282,
  31. "highlight": {
  32. "title": [
  33. "<em>我是中国人</em>"
  34. ]
  35. }
  36. }
  37. ]
  38. }
  39. }

从返回结果中可以看到,虽然没有保存title字段到_source, 但是依然可以实现搜索高亮。

四、总结

通过图解和代码测试,对Elasticsearch中的_source、_all、store和index进行了详解,相信很容易明白。错误和疏漏之处,欢迎批评指正。

图解elasticsearch的_source、_all、store和index的更多相关文章

  1. Elasticsearch学习之图解Elasticsearch中的_source、_all、store和index属性

    转自 : https://blog.csdn.net/napoay/article/details/62233031 1. 概述 Elasticsearch中有几个关键属性容易混淆,很多人搞不清楚_s ...

  2. 浅析ES的_source、_all、store、index

    Elasticsearch中有大量关键概念容易混淆,对于初学者来说是噩梦: _source字段里存储了什么? index属性的作用是什么? 何时应该开启_all字段? store属性和_source字 ...

  3. ES索引瘦身 压缩——_source _all 均disable filed store为no,引入第三方DB存储原始数据,去掉pos倒排和doc_values,强制定期merge segments,将所有fileds合并为一个field big string

    原始数据:835MB ES 设置了_source _all disabled 且设置了仅仅存docs倒排Wed Feb 22 11:58:27 CST 2017Before size:1 /home/ ...

  4. Elasticsearch 5.0 _all field的简单认识

    前言:本文的目的是为后续磁盘空间利用优化做铺垫,主要知识点来源于官网 一._all 是什么 在Elasticsearch中,_all field维护这一个很大的字符串数组(text类型).这个字符串是 ...

  5. 解决:ElasticSearch ClusterBlockException[blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];

    简记 使用SkyWalking用ES做存储,发现运行一段时间会提示ElasticSearch ClusterBlockException[blocked by: [FORBIDDEN/12/index ...

  6. 图解Elasticsearch中的_source、_all、store和index属性

    https://blog.csdn.net/napoay/article/details/62233031

  7. elasticsearch中mapping的_source和store的笔记

    0.故事引入 无意中看到了ES的mapping中有store字段,作为一个ES菜鸡,有必要对这个字段进行下笔记. 1._source _source字段我在们进行检索时相当重要, ES默认检索只会返回 ...

  8. elasticsearch中mapping的_source和store的笔记(转)

    原文地址: https://www.cnblogs.com/zklidd/p/6149120.html 0.故事引入 无意中看到了ES的mapping中有store字段,作为一个ES菜鸡,有必要对这个 ...

  9. Elasticsearch学习随笔(二)-- Index 和 Doc 查询新建API总结

    本文着重总结Elasticsearch的常见API了,进行分析. Index API 初始化Index,设置shards和replica PUT http://localhost:9200/firew ...

随机推荐

  1. 六.HashMap HashTable HashSet区别剖析总结

    HashMap.HashSet.HashTable之间的区别是Java程序员的一个常见面试题目,在此仅以此博客记录,并深入源代码进行分析: 在分析之前,先将其区别列于下面: 1.HashSet底层采用 ...

  2. 【二】JConsole、VisualVM

    监控工具 jconsole.exe 只有10几k,真正的代码是包装在tools.jar中. 双击[本地线程]:sun.tools.jconsole.JConsole: 内存的线在上下起伏,证明是[垃圾 ...

  3. Android 常见异常及解决办法

    Ø  前言 本文主要记录 Android 的常见异常及解决办法,以备以后遇到相同问题时可以快速解决. 1.   java.lang.NullPointerException: Attempt to i ...

  4. 使用 JS 实现文字上下跑马灯

    Ø  前言 今天在做商城首页时,遇到一个上下跑马灯功能,因为之前也只是接触过左右的跑马灯,一时还不知道从何下手.在网上看了几个 demo,并亲自运行了一下,是可以实现的.但是,能运行不知其所以然也不行 ...

  5. 使用select的str_cli函数的实现

    void str_cli(FILE *fp, int sockfd) { int maxfdp1; fd_set rset; char sendline[MAXLINE], recvline[MAXL ...

  6. Linux centos 防火墙篇

    防火墙的关闭 service iptables stop 永久关闭 chkconfug iptables off 查看状态 service iptables status

  7. MySQL图形化管理工具

    PHPMyAdmin(关于web界面的) Navicat MySQL Workbench

  8. C++ 类2

    继承: 联系一起的类有层次关系. 基类: 层次关系的根部 派生类: 基类负责定义在层次关系中所以类共同拥有的成员,派生类定义其各种特有的成员. 基类类型相关的函数, 派生类不做改变直接继承的函数 某些 ...

  9. matplotlib-区域填充

    import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import datetime #解决能显示中文 ...

  10. 第25月第15天 udacity cs253

    1.cs253 https://classroom.udacity.com/courses/cs253 webapp2 Install WebOb, Paste and webapp2¶ We nee ...