ElasticSearch之updateByQuery使用

#背景

有时需要通过某些查询条件,更新文档某一个字段,这样的诉求,用SQL表达就是update t_student set class=’优秀的小男生’ where age = 10 and score = 100 and sex = 1。ES有updateByQuery API 和 deleteByQuery API,这样一条DSL就可以搞定类似的需求。

例子

批量更新id = 9627361的文档,admin_rank数值++,address更新成”我是_update_by_query”,name_alias_array字段,更新为一个集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST hotel_20190513/hotel/_update_by_query
{
"script": {
"inline": "ctx._source.admin_rank++;ctx._source['address']='我是_update_by_query';ctx._source['name_alias_array']=['哈哈','hei嘿']",
"lang": "painless"
},
"query": {
"bool": {"must": [
{"term": {
"id": {
"value": 9627361
}
}}
]}
}
}

删除entity_type = hotel_name的所有文档。

1
2
3
4
5
6
7
8
9
10
POST entity_hotel_20190528/entity_hotel/_delete_by_query
{
"query": {
"term": {
"entity_type": {
"value": "hotel_name"
}
}
}
}

golang例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
updateByQuery := client.UpdateByQuery().Query(elastic.NewTermQuery("entity_id", node.TagId)).Script(elastic.NewScriptInline(script)).Index(index).Type(indexType)
out, err := updateByQuery.Do(context.TODO())
if err != nil {
panic(err)
}
b, err := json.Marshal(out)
if err != nil {
panic(err)
}
got := string(b)
updated := tool.GoJson(got).Get("updated").ToString()
if tool.IsEmpty(updated) {
updated = "0"
}
println("执行成功.tagId=" + tool.ToString(node.TagId) + "更新" + updated + "个文档.")

参考文档

官方文档

ElasticSearch集群的搭建

#相关技术点

in-memory buffer是通过refresh操作写到文件缓冲区的,refresh的过程除了在文件缓冲区生成这个文件以外,还会让底层Lucene的index reader打开这个文件,让新生成的这个文件对搜索可见。

周五的时候跟同事讨论下了,不知道这样理解对不对–refresh类似于 outputstream flush(此时数据从 java heap 写到 memory buffer),之后(按照大神上面说的)index reader读取新文件,然后等待触发flush(这个则类似于 outputstream close,此时数据从 memory buffer 写到 disk),请大神赐教

集群配置

集群包括3台物理机共12个节点,每台物理机部署1个Master节点,1个Client节点,2个Data节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# ---------------------------------- Cluster -----------------------------------
#集群名称
cluster.name:
# ------------------------------------ Node ------------------------------------
#节点名称
node.name:
#是否是Master Node
node.master: true
#是否是Data Node
node.data: false
#是否是Ingest Node
node.ingest: false
node.attr.rack: first
# ----------------------------------- Paths ------------------------------------
# Path to log files:
#可以指定es的数据存储目录,默认存储在es_home/data目录下
#path.data: /path/to/data
#可以指定es的日志存储目录,默认存储在es_home/logs目录下
#path.logs: /path/to/logs
# ----------------------------------- Memory -----------------------------------
#锁定物理内存地址,防止elasticsearch内存被交换出去,也就是避免es使用swap交换分区
bootstrap.memory_lock: true
#CentOS下不支持SecComp,故而需要设置成false
bootstrap.system_call_filter: false
# ---------------------------------- Network -----------------------------------
network.host: 192.168.1.97
http.port: 9200
transport.tcp.port: 9300
# --------------------------------- Discovery ----------------------------------
#
discovery.zen.ping.unicast.hosts: ["192.168.1.97:9300","192.168.1.98:9300","192.168.1.113:9300"]
#理论上是 masternum/2+1,防止脑裂
discovery.zen.minimum_master_nodes: 2
# ---------------------------------- Various -----------------------------------
xpack.security.enabled: false
#支持跨域访问
http.cors.enabled: true
http.cors.allow-origin: "*"

参考文档

Linux sandboxing机制

从内核文件系统看文件读写过程

ElasticSearch Scroll

ElasticSearch Scroll

##深分页

比如pageIndex=10,pageSize=20,{“start”: 180, “size”: 20},相当于每个分片召回了200条数据,排序之后截断前20条返回。但是如果pageIndex=1000,每个分片需要召回20000条数据,排序,最后仍然是取前20条,扔掉19980条。深分页的实现方式代价是很大的。

Scroll

为了解决以上深分页,在页码太大情况下性能的问题,ES提供了Scroll方式。

scroll 查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。

游标查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 cursor 。

游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 视图 一样。

深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段 _doc 来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。

启用游标查询可以通过在查询的时候设置参数 scroll 的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。

例如:依据查询条件开启滚动,镜像有效期为5分钟。这个查询结果中包含scroll_id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
curl -XPOST 'http://localhost:9200/es_cluster/goods_index/goods/_search?scroll=5m' -d '{
"size": 20,
"query": {
"bool": {
"filter": [
{
"exists": {
"field": "skuUpTime"
}
}
]
}
}
}'

下次查询的时候,就可以直接用scroll_id来查询了

1
2
3
4
curl -XPOST 'http://localhost:9200/es_cluster/scroll' -d '{
"scroll": "5m",
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoJgAAAAA8lsqeFjRwN19JcDBKVFd1cy04dkZucUZ4dHcAAAAAPlQH_BZIMUU1VFA2dVIxMk10M0xoWW1sSEtRAAAAADtYOdcWUVBlYXZCNmRTSEtXV2llZTE4dkEwZwAAAAA6dfbHFkdEMS1VY21CVHFhSFpFS1ZrVnBwSVEAAAAAPaL6vBZsZmRFeHRBeFFJaWlVOXNWV2xnZlB3AAAAADy6UDUWRU9NVVRadG5STnV4cThrb2VMdHhqUQAAAAA9V-f6FnNYSV83SHZVVHpDTHVLZWFiNmVwcVEAAAAAPMlOFhY5Zk5ESlBZdFI5bVVEclI4b2paTld3AAAAADn6zjwWZEJ5RU9VOThTUW1HUnB5UzlOT18xUQAAAAA9EBaGFmM4Ykh6SHkxU3JPYkFFRFZMWVRiQUEAAAAAPSKSJxZVUlRzY0luTFJTQzQ3WTZydUxoQVN3AAAAADyw6E4WS21DZHdWX21TRXlkdzVvYUpRcVBKUQAAAAA7sX3BFnh4UC1rMGhDU1FlZFFSdjVDVVc0d3cAAAAAPMIY9RZla0lLajhFQlMtYUVOZDE1U0tXekRnAAAAADtYOdgWUVBlYXZCNmRTSEtXV2llZTE4dkEwZwAAAAA5-s49FmRCeUVPVTk4U1FtR1JweVM5Tk9fMVEAAAAAPMlOFxY5Zk5ESlBZdFI5bVVEclI4b2paTld3AAAAADzjiUkWMll6VHRaUDRUV2VjNXA4LUxfMlFxdwAAAAA8cKq6FndTQ2JfOWlWUXlHNHdNMUZ3ejZVZUEAAAAAPHCquRZ3U0NiXzlpVlF5RzR3TTFGd3o2VWVBAAAAADzx948Wdlk0dzdJWnBRWHEyRWFsVEhsVUdiQQAAAAA9cxFHFnpwdy1EaXFXUmR5REM5ZW5CYTB0ZEEAAAAAPXMRSBZ6cHctRGlxV1JkeURDOWVuQmEwdGRBAAAAAD1DIxMWM0E3dW1PbkVUQzZMSUJXV21LaHNiZwAAAAA9QyMUFjNBN3VtT25FVEM2TElCV1dtS2hzYmcAAAAAPPeZ9hZyY0luUVRFb1RsNmF1YWhZaVEwWUFBAAAAADz3mfcWcmNJblFURW9UbDZhdWFoWWlRMFlBQQAAAAA6pq_PFjRDZjN6XzBSU25DRE5PWlA2RFRUR2cAAAAAOqavzhY0Q2Yzel8wUlNuQ0ROT1pQNkRUVEdnAAAAADzcYCcWQ2xwZk15U01RNk9oelRQR2w2bTRmdwAAAAA84x3vFk8wYjdmdV9aU2E2QzREc045bUx4UUEAAAAAPPTj5RZoYlctclkyblM3cXpDeEZTa05FNlNnAAAAADzrVQEWLU9xeUFOVHRUQTZtd2R2eG5MTF96UQAAAAA861UAFi1PcXlBTlR0VEE2bXdkdnhuTExfelEAAAAAO1D_vBZheEpkUFp4UFNXS19BWDdvMTNkS1BnAAAAADuxfcIWeHhQLWswaENTUWVkUVJ2NUNVVzR3dwAAAAA7ungNFlpqWVViMnZsVDU2LXg4VzBlTlZ0cWcAAAAAPaL6vRZsZmRFeHRBeFFJaWlVOXNWV2xnZlB3"
}'

elasticSearch系列笔记(5)-客户端负载均衡

常用负载均衡策略

ES客户端负载均衡策略

集群嗅探

elasticSearch系列笔记(1)-Hello ElasticSearch

读了上面的小故事,是不是觉得对ElasticSearch的前世今生,兴趣十足呢?!我计划写一篇ElasticSearch的系列学习笔记,深入浅出,不仅方便大家学习,还能够让我更加深入的了解这门技术。学习一门新技术的第一课就是hello world.
接下来的章节,实操ElasticSearch hello world。

ElasticSearch简介

回忆时光

       
许多年前,一个刚结婚的名叫 Shay Banon 的失业开发者,跟着他的妻子去了伦敦,他的妻子在那里学习厨师(感觉国内的女生很少有喜欢做饭的,反而男生喜欢做饭)。 在寻找一个赚钱的工作的时候,为了给他的妻子做一个食谱搜索引擎,他开始使用 Lucene 的一个早期版本。

       
直接使用 Lucene 是很难的,因此 Shay 开始做一个抽象层,Java 开发者使用它可以很简单的给他们的程序添加搜索功能。 他发布了他的第一个开源项目 Compass。

       
后来 Shay 获得了一份工作,主要是高性能,分布式环境下的内存数据网格。这个对于高性能,实时,分布式搜索引擎的需求尤为突出, 他决定重写 Compass,把它变为一个独立的服务并取名 Elasticsearch。

       
第一个公开版本在2010年2月发布,从此以后,Elasticsearch 已经成为了 Github 上最活跃的项目之一,他拥有超过300名 contributors(目前736名 contributors )。 一家公司已经开始围绕 Elasticsearch 提供商业服务,并开发新的特性,但是,Elasticsearch 将永远开源并对所有人可用。

       
据说,Shay 的妻子还在等着她的食谱搜索引擎…

切入正题

       
读了上面的小故事,是不是觉得对ElasticSearch的前世今生,兴趣十足呢?!我计划写一篇ElasticSearch的系列学习笔记,深入浅出,不仅方便大家学习,还能够让我更加深入的了解这门技术。学习一门新技术的第一课就是hello world.
接下来的章节,实操ElasticSearch hello world。

Mac ElasticSearch 安装

1、Java环境的安装配置

2、brew install elasticSearch(仅适用于Mac)

3、brew info elasticSearch,会显示如下信息表示安装成功

elasticSearch: stable 6.2.4, HEAD
Distributed search & analytics engine
https://www.elastic.co/products/elasticsearch
/usr/local/Cellar/elasticSearch/6.2.4 (112 files, 30.8MB)
  Built from source on 2018-05-29 at 11:10:53
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/elasticsearch.rb
==> Requirements
Required: java = 1.8 ✔
==> Options
--HEAD
    Install HEAD version
==> Caveats

4、brew services start elasticsearch

启动后localhost:9200,打印如下,说明ElasticSearch启动成功
{
  "name" : "yptOhLD",
  "cluster_name" : "elasticsearch_1",
  "cluster_uuid" : "_na_",
  "version" : {
    "number" : "6.2.4",
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

5、brew install kibana(仅适用于Mac)
6、brew services start kibana

7、打开kibana localhost:5601

基于以上7个步骤,环境问题搞定,下面来真实的操作一下ElasticSearch。

ElasticSearch Hello World

创建索引(create index)

curl -XPUT "http://localhost:9200/goods_index"

curl -XGET "http://localhost:9200/goods_index"

{
  "goods_index": { #索引名称
    "aliases": {},
    "mappings": {},
    "settings": {
      "index": {
        "creation_date": "1530627979046",
        "number_of_shards": "5", #5个分片
        "number_of_replicas": "1", #一个备份
        "uuid": "kTy_hHlQQRaVPygKHZpUYQ",
        "version": {
          "created": "6020499"
        },
        "provided_name": "goods_index"
      }
    }
  }
}

索引文档(index document)

curl -XPUT "http://localhost:9200/goods_index/goods/12343333" -H 'Content-Type:application/json' -d'
{
  "skuName": "华为手机",
  "url":"https://item.jd.com/6946605.html"
}'

索引数据之后,再执行查看索引详情,会发现mappings属性多了一个名字叫goods的type,goods下面多了skuName和url两个properties。
{
  "goods_index": {
    "aliases": {},
    "mappings": {
      "goods": {
        "properties": {
          "skuName": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "url": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    },
    "settings": {
      "index": {
        "creation_date": "1530627979046",
        "number_of_shards": "5",
        "number_of_replicas": "1",
        "uuid": "kTy_hHlQQRaVPygKHZpUYQ",
        "version": {
          "created": "6020499"
        },
        "provided_name": "goods_index"
      }
    }
  }
}

查询文档(query document)

curl -XGET "http://localhost:9200/goods_index/goods/_search"

执行上面的查询语句,得到如下的结果集。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "goods_index",
        "_type": "goods",
        "_id": "12343333",
        "_score": 1,
        "_source": {
          "skuName": "华为手机",
          "url": "https://item.jd.com/6946605.html"
        }
      }
    ]
  }
}

小节

       
ElasticSearch的Hello world,是不是比java,python难一些呢?不过还好,一个检索系统,就此拉开了帷幕。这就是ElasticSearch推崇的“开箱即用”的理念。但是要学好ElasticSearch可不是一件容易的事情,细心的同学,可能会发现有一些细节:

1、什么是索引?

2、什么是文档?

3、索引和文档是什么样的关系?

……

请持续关注我的博客,我们逐渐从ElasticSearch小白,变成大牛。

参考文献

elasticSearch权威指南2.x

elasticSearch reference 6.2

elasticSearch系列笔记(4)-elasticSearch搜索类型

ElasticSearch本地源码调试

转自:https://donlianli.iteye.com/blog/2094305

es在查询时,可以指定搜索类型为QUERY_THEN_FETCH,QUERY_AND_FEATCH,DFS_QUERY_THEN_FEATCH和DFS_QUERY_AND_FEATCH。那么这4种搜索类型有什么区别?

分布式搜索背景介绍:

ES天生就是为分布式而生,但分布式有分布式的缺点。比如要搜索某个单词,但是数据却分别在5个分片(Shard)上面,这5个分片可能在5台主机上面。因为全文搜索天生就要排序(按照匹配度进行排名),但数据却在5个分片上,如何得到最后正确的排序呢?ES是这样做的,大概分两步。

step1、ES客户端会将这个搜索词同时向5个分片发起搜索请求,这叫Scatter,

step2、这5个分片基于本Shard独立完成搜索,然后将符合条件的结果全部返回,这一步叫Gather。

客户端将返回的结果进行重新排序和排名,最后返回给用户。也就是说,ES的一次搜索,是一次scatter/gather过程(这个跟mapreduce也很类似).

然而这其中有两个问题。

第一、数量问题。比如,用户需要搜索”双黄连”,要求返回最符合条件的前10条。但在5个分片中,可能都存储着双黄连相关的数据。所以ES会向这5个分片都发出查询请求,并且要求每个分片都返回符合条件的10条记录。当ES得到返回的结果后,进行整体排序,然后取最符合条件的前10条返给用户。这种情况,ES5个shard最多会收到10*5=50条记录,这样返回给用户的结果数量会多于用户请求的数量。

第二、排名问题。上面搜索,每个分片计算分值都是基于自己的分片数据进行计算的。计算分值使用的词频率和其他信息都是基于自己的分片进行的,而ES进行整体排名是基于每个分片计算后的分值进行排序的,这就可能会导致排名不准确的问题。如果我们想更精确的控制排序,应该先将计算排序和排名相关的信息(词频率等)从5个分片收集上来,进行统一计算,然后使用整体的词频率去每个分片进行查询。

这两个问题,估计ES也没有什么较好的解决方法,最终把选择的权利交给用户,方法就是在搜索的时候指定query type。

1、query and fetch

向索引的所有分片(shard)都发出查询请求,各分片返回的时候把元素文档(document)和计算后的排名信息一起返回。这种搜索方式是最快的。因为相比下面的几种搜索方式,这种查询方法只需要去shard查询一次。但是各个shard返回的结果的数量之和可能是用户要求的size的n倍。

2、query then fetch(默认的搜索方式)

如果你搜索时,没有指定搜索方式,就是使用的这种搜索方式。这种搜索方式,大概分两个步骤,第一步,先向所有的shard发出请求,各分片只返回排序和排名相关的信息(注意,不包括文档document),然后按照各分片返回的分数进行重新排序和排名,取前size个文档。然后进行第二步,去相关的shard取document。这种方式返回的document与用户要求的size是相等的。

3、DFS query and fetch

这种方式比第一种方式多了一个初始化散发(initial scatter)步骤,有这一步,据说可以更精确控制搜索打分和排名。

4、DFS query then fetch

比第2

方式多了一个

初始化散发(initial scatter)步骤。

DSF是什么缩写?初始化散发是一个什么样的过程?

从es的官方网站我们可以指定,初始化散发其实就是在进行真正的查询之前,先把各个分片的词频率和文档频率收集一下,然后进行词搜索的时候,各分片依据全局的词频率和文档频率进行搜索和排名。显然如果使用DFS_QUERY_THEN_FETCH这种查询方式,效率是最低的,因为一个搜索,可能要请求3次分片。但,使用DFS方法,搜索精度应该是最高的。

至于DFS是什么缩写,没有找到相关资料,这个D可能是Distributed,F可能是frequency的缩写,至于S可能是Scatter的缩写,整个单词可能是分布式词频率和文档频率散发的缩写。

总结一下,从性能考虑QUERY_AND_FETCH是最快的,DFS_QUERY_THEN_FETCH是最慢的。从搜索的准确度来说,DFS要比非DFS的准确度更高。

mac安装mysql记录

1
brew install mysql

CREATE USER ‘test‘@’%’ IDENTIFIED BY ‘root@12’;

grant all privileges on . to ‘test‘@’%’;

Flush privileges;

下载Sequel Pro开始使用

ElasticSearch系列笔记(2)-ElasticSearch 理论基础

本节主要介绍下ElasticSearch 理论基础。知其然知其所以然,如下的理论和算法,就是ElasticSearch的魂!

elasticSearch系列笔记(3)-elastic本地源码调试

ElasticSearch本地源码调试

转自:https://www.felayman.com/articles/2017/11/10/1510291087246.html

Elasticsearch版本为 5.5.1

1. 源码下载

2. 分支切换

  • git checkout v5.5.1

3 运行gradle idea,gradle build -x test

如果运行gradle idea会报如下错误:请修改elasticsearch源文件中的BuildPlugin.groory文件中的findJavaHome()方法的第一行代码,源码为 String javaHome = System.getenv(‘JAVA_HOME’),修改为String javaHome = “你的JAVA_HOME地址,输入echo $JAVA_HOME($)”

1
2
3
4
What went wrong:
A problem occurred evaluating project ':benchmarks'.
> Failed to apply plugin [id 'elasticsearch.build']
> JAVA_HOME must be set to build Elasticsearch

这里我使用的是idea工具来调试源码,因此先不要用idea导入该项目,而是进入到下载的elasticsearch目录下,执行gradle idea,等待漫长的依赖下载,等待下载完成后 执行 gradle build -x test 对源码进行编译,等待编译完成.

4. 注释掉jar hell相关代码

  • 全局搜索JarHell.checkJarHell,以及checkJarHell,注释掉相应的代码,否则运行会报错

5. 配置Edit Configuation

  • mainClass为 org.elasticsearch.bootstrap.Elasticsearch VM options为
  • Des.path.home=/Users/admin/elk/elasticsearch-5.5.0 -Dlog4j2.disable.jmx=true

6. 运行org.elasticsearch.bootstrap.Elasticsearch中的main方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 [2017-07-11T22:00:08,396][INFO ][o.e.n.Node               ] [] initializing ...
[2017-07-11T22:00:08,487][INFO ][o.e.e.NodeEnvironment ] [iobPZcg] using [1] data paths, mounts [[/ (/dev/disk1)]], net usable_space [133.3gb], net total_space [232.6gb], spins? [unknown], types [hfs]
[2017-07-11T22:00:08,487][INFO ][o.e.e.NodeEnvironment ] [iobPZcg] heap size [3.5gb], compressed ordinary object pointers [true]
[2017-07-11T22:00:08,503][INFO ][o.e.n.Node ] node name [iobPZcg] derived from node ID [iobPZcgEQBKodmURFuo_Gw]; set [node.name] to override
[2017-07-11T22:00:08,503][INFO ][o.e.n.Node ] version[5.5.0-SNAPSHOT], pid[65630], build[Unknown/Unknown], OS[Mac OS X/10.12/x86_64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_101/25.101-b13]
[2017-07-11T22:00:08,503][INFO ][o.e.n.Node ] JVM arguments [-Des.path.home=/Users/admin/elk/elasticsearch-5.5.0, -Dlog4j2.disable.jmx=true, -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=49964:/Applications/IntelliJ IDEA.app/Contents/bin, -Dfile.encoding=UTF-8]
[2017-07-11T22:00:08,504][WARN ][o.e.n.Node ] version [5.5.0-SNAPSHOT] is a pre-release version of Elasticsearch and is not suitable for production
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [aggs-matrix-stats]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [ingest-common]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [lang-expression]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [lang-groovy]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [lang-mustache]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [lang-painless]
[2017-07-11T22:00:09,201][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [parent-join]
[2017-07-11T22:00:09,202][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [percolator]
[2017-07-11T22:00:09,202][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [reindex]
[2017-07-11T22:00:09,202][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [transport-netty3]
[2017-07-11T22:00:09,202][INFO ][o.e.p.PluginsService ] [iobPZcg] loaded module [transport-netty4]
[2017-07-11T22:00:09,202][INFO ][o.e.p.PluginsService ] [iobPZcg] no plugins loaded
[2017-07-11T22:00:11,386][INFO ][o.e.d.DiscoveryModule ] [iobPZcg] using discovery type [zen]
[2017-07-11T22:00:12,068][INFO ][o.e.n.Node ] initialized
[2017-07-11T22:00:12,068][INFO ][o.e.n.Node ] [iobPZcg] starting ...
[2017-07-11T22:00:12,120][INFO ][i.n.u.i.PlatformDependent] Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system instability.
[2017-07-11T22:00:12,291][INFO ][o.e.t.TransportService ] [iobPZcg] publish_address {127.0.0.1:9300}, bound_addresses {[fe80::1]:9300}, {[::1]:9300}, {127.0.0.1:9300}
[2017-07-11T22:00:12,308][WARN ][o.e.b.BootstrapChecks ] [iobPZcg] initial heap size [268435456] not equal to maximum heap size [4294967296]; this can cause resize pauses and prevents mlockall from locking the entire heap
[2017-07-11T22:00:15,383][INFO ][o.e.c.s.ClusterService ] [iobPZcg] new_master {iobPZcg}{iobPZcgEQBKodmURFuo_Gw}{J8yIAMTeS3uOKeW35gG0kw}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)
[2017-07-11T22:00:15,408][INFO ][o.e.h.n.Netty4HttpServerTransport] [iobPZcg] publish_address {127.0.0.1:9200}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9200}
[2017-07-11T22:00:15,409][INFO ][o.e.n.Node ] [iobPZcg] started
[2017-07-11T22:00:15,639][INFO ][o.e.g.GatewayService ] [iobPZcg] recovered [2] indices into cluster_state
[2017-07-11T22:00:15,850][INFO ][o.e.c.r.a.AllocationService] [iobPZcg] Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[twitter][3]] ...]).

可能遇到的异常

  • ERROR: the system property [es.path.conf] must be set

    原因是没有指定es.path.conf,设置-Des.path.conf=你调试源码版本对应的conf目录

  • Exception in thread “main” java.lang.IllegalStateException: path.home is not configured

    原因是因为没有为elasticsearch配置path.home参数,可以在Edit Configuation中设置虚拟机参数:-Des.path.home=你下载的对应的elasticsearch的安装目录,这么做的原因
    是elasticsearch在启动中会加载一些默认配置以及插件,我们直接加载elasticsearch安装目录下的配置和插件即可,后面会在源码中体现

  • 2017-06-23 14:00:44,760 main ERROR Could not register mbeans java.security.AccessControlException: access denied (“javax.management.MBeanTrustPermission” “register”)

    原因是因为elasticsearch在启动过程中使用到了jmx,我们这里禁止使用即可,配置也是在Edit Configuation中设置虚拟机参数 -Dlog4j2.disable.jmx=true

  • org.elasticsearch.bootstrap.StartupException: org.elasticsearch.bootstrap.BootstrapException: java.lang.IllegalStateException: jar hell!或Classname: org.elasticsearch.search.aggregations.matrix.MatrixAggregationPlugin due to jar hell

    原因是因为elasticsearch中大量存在一个类或一个资源文件存在多个jar中,我们注释掉相应代码即可,主要是PluginsService中374行的JarHell.checkJarHell(union)以及
    Bootstrap中220行的JarHell.checkJarHell(),最简单的方式就是将JarHell.checkJarHell()中的方法体注释掉

  • org.elasticsearch.bootstrap.StartupException: java.lang.IllegalArgumentException: plugin [aggs-matrix-stats] is incompatible with version [7.0.0-alpha1]; was designed for version [5.6.1]

    原因是一般情况下我们调试的源码非某个发布版本,有些配置项并未发布,我们的配置与当前代码的版本匹配不上,这个时候我们需要将调试的源码设置成某个发布版本,一般来说,Elasticsearch每发布
    一个稳定版本,都会有一个对应的tag,我们进入到ES源码目录下执行git tag, 我这里调试的版本为v5.6.1,所以执行git checkout v5.6.1,切换到v5.6.1tag.

另一种源码调试方式:远程调试

如果上面第五个报错之后解决不了无法继续进行,可以选择这种方式:

在 Elasticsearch 源码目录下打开 CMD,输入下面的命令启动一个 debug 实例

1
gradle run --debug-jvm

如果启动失败可能需要先执行 gradle cleangradle run --debug-jvm 或者 先退出 IDEA

在 IDEA 中打开 Edit Configurations,添加 remote

配置 host 和 port

点击 debug,浏览器访问 http://localhost:9200/,即可看到ES返回的信息

随机调试一下, 打开 elasticsearch/server/src/main/org/elasticsearch/rest/action/cat 下的 RestHealthAction 类,在第 54 行出设置一个断点,然后浏览器访问 http://localhost:9200/_cat/health,可以看到断点已经捕获到该请求了

运行成功,可以开始设置断点进行其他调试

源码本地编译工程包

在es源码根目录,执行 gradle assemble 命令,编译好之后工程ZIP包位于下图位置。

img

其他可能遇到的问题

1. 错误信息如下

1
JAVA8_HOME required to run tasks gradle

配置环境变量 JAVA8_HOME,值为 JDK8 的安装目录

2. 错误信息如下

1
2
3
4
5
6
7
[2018-08-22T13:07:23,197][INFO ][o.e.t.TransportService   ] [EFQliuV] publish_address {10.100.99.118:9300}, bound_addresses {[::]:9300}
[2018-08-22T13:07:23,211][INFO ][o.e.b.BootstrapChecks ] [EFQliuV] bound or publishing to a non-loopback address, enforcing bootstrap checks
ERROR: [1] bootstrap checks failed
[1]: initial heap size [268435456] not equal to maximum heap size [4273995776]; this can cause resize pauses and prevents mlockall from locking the entire heap
[2018-08-22T13:07:23,219][INFO ][o.e.n.Node ] [EFQliuV] stopping ...
2018-08-22 13:07:23,269 Thread-2 ERROR No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'log4j2.debug' to show Log4j2 internal initialization logging.
Disconnected from the target VM, address: '127.0.0.1:5272', transport: 'socket'

Edit ConfigurationsVM options 加入下面配置

-Xms2g
-Xmx2g

参考文献

elasticSearch权威指南2.x

elasticSearch reference 6.2

http://laijianfeng.org/2018/08/%E6%95%99%E4%BD%A0%E7%BC%96%E8%AF%91%E8%B0%83%E8%AF%95Elasticsearch-6-3-2%E6%BA%90%E7%A0%81/