Hbase系列5-javademo

基于Hadoop2.7.1 + Hbase 1.2.1 + HbaseClientAPI 1.2.8

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package com.jd.union.spark

import java.io.IOException
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util
import java.util._

import org.apache.hadoop.hbase._
import org.apache.hadoop.hbase.client.{ConnectionFactory, HBaseAdmin, _}
import org.apache.hadoop.hbase.util.Bytes

object SkuDataToHBaseJob extends Serializable {
val dateFormat = new SimpleDateFormat("yyyyMMdd")

var conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.quorum", "192.168.2.100")
conf.set("hbase.zookeeper.property.clientPort", "2181")
val conn = ConnectionFactory.createConnection(conf)


def main(args: Array[String]): Unit = {
val skuId = "129399424324"
val orKey = dateFormat.format(new Date()) + "$" + skuId
//todo 取前四位 + skuId + date 当做rowkey,避免热点数据
val rowkey = md5(orKey)
val data: String = " {\"abParam\":\"nature\",\"abVersion\":\"comm\",\"adowner\":\"p_10026704\",\"bestCouponId\":\"92737319\",\"brandCode\":382820,\"brandName\":\"谷邦(GUBANG)\",\"cid1\":1620,\"cid1Name\":\"家居日用\",\"cid2\":13780,\"cid2Name\":\"收纳用品\",\"cid3\":13785,\"cid3Name\":\"收纳架/篮\",\"color\":\"2个装北欧粉\",\"comments\":11,\"couponId\":0,\"couponLink\":\"\",\"createTime\":\"2019-01-22T05:44:42.969Z\",\"deliveryType\":0,\"endTime\":\"2999-01-01 23:59:59\",\"goodComments\":11,\"goodCommentsShare\":100,\"hasCoupon\":1,\"imageUrl\":\"jfs/t1/10013/33/7229/24225/5c286dfaEacd0c6a2/f16290038d59eea6.jpg\",\"imgList\":\"jfs/t1/8948/19/11086/256803/5c286df9E594f189f/5a2af0eeda043878.jpg|jfs/t1/23576/23/3598/256769/5c286df9E1e32d799/62ced8312a144260.jpg|jfs/t1/10013/33/7229/24225/5c286dfaEacd0c6a2/f16290038d59eea6.jpg|jfs/t1/26566/34/4201/410351/5c2f5aa6Eb441c098/fc86afded2d6334d.png|jfs/t1/20665/7/3549/279989/5c286dfaE5a253816/1dfab92f62045e00.jpg|jfs/t1/20297/14/3513/296706/5c286df4Efecc5d55/971d9dad36ea6788.jpg\",\"inOrderComm30Days\":129.07,\"inOrderComm30DaysSku\":84.35,\"inOrderCount30Days\":58,\"inOrderCount30DaysSku\":36,\"isCare\":0,\"isHot\":1,\"isLock\":0,\"isNew\":0,\"isOversea\":0,\"isPinGou\":1,\"isSeckill\":0,\"isStuPrice\":0,\"itemTag\":0,\"lowestPrice\":9.90,\"majorSuppBrevityCode\":\"\",\"orientationFlag\":0,\"owner\":\"p\",\"pcCommission\":5.97,\"pcCommissionShare\":30.0,\"pcPrice\":19.90,\"pid\":40520301670,\"pingouActiveId\":15461534722120,\"pingouEnd\":\"2037-08-16 09:30:48\",\"pingouPrice\":9.90,\"pingouStart\":\"2018-12-30 15:05:02\",\"pingouTmCount\":2,\"planId\":1507475989,\"qualityScore\":0.0631,\"qualityScoreNew\":0.4147,\"rfId\":0,\"ruleType\":7,\"seckillOriPrice\":0.0,\"seckillPrice\":0.0,\"shelvesTm\":\"2018-12-30 15:04:32.0\",\"shopId\":863648,\"size\":\"\",\"skuId\":40520301670,\"skuName\":\"谷邦-两个装卫生间牙刷架壁挂式免打孔浴室置物吸盘梳子筒座牙膏杯吸壁收纳盒 2个装北欧粉\",\"startTime\":\"2019-01-11 00:00:00\",\"stuPrice\":0.0,\"themeFlag\":2,\"unionCoupon\":[{\"batchId\":92737319,\"beginTime\":\"2019-01-10 14:22:00\",\"couponKind\":3,\"couponType\":1,\"createTime\":\"2019-01-18T09:50:26.589Z\",\"createUser\":\"lisen43\",\"discount\":8.0,\"endTime\":\"2019-01-31 14:23:00\",\"expireType\":5,\"key\":\"3172a45b3f8242d2ba92141a7c26b66d\",\"link\":\"http://coupon.m.jd.com/coupons/show.action?key=3172a45b3f8242d2ba92141a7c26b66d&roleId=17184533&to=mall.jd.com/index-863648.html\",\"ownerType\":\"92,95,444,498\",\"platformType\":0,\"quota\":17.0,\"remainCnt\":19965,\"source\":3,\"updateTime\":\"2019-01-18T09:50:26.589Z\",\"useEndTime\":\"2019-01-31 23:59:59\",\"useStartTime\":\"2019-01-10 00:00:00\",\"venderId\":10026704}],\"updateTime\":\"2019-01-22T15:01:31.194Z\",\"venderName\":\"谷邦家居拼购店\",\"vid\":10026704,\"wareId\":12567523910,\"wlCommission\":5.97,\"wlCommissionShare\":30.0,\"wlPrice\":19.90}"
val tableName = "union_search_sku"
try {
addData(rowkey, tableName, "cf", "value", data)
get(rowkey, tableName)
println("scan----------------")
scan(tableName)
//createTable("admin_create")
//del(tableName, "20190909$2")
println("创建表成功")
} catch {
case e: Exception => {
e.printStackTrace()
null
}
} finally {
}
}


def md5(source: String): String = {
val sb = new StringBuffer(32)
try {
val md = MessageDigest.getInstance("MD5")
val bytes = md.digest(source.getBytes("utf-8"))

for (i <- 0 to bytes.length) {
sb.append(Integer.toHexString((bytes.apply(i) & 0xFF) | 0x100).toLowerCase().substring(1, 3))
}
} catch {
case e: Exception => null
}
sb.toString()
}

@throws[IOException]
def addData(rowKey: String, tableName: String, cf: String, column: String, value: String): Unit = {
val put = new Put(Bytes.toBytes(rowKey))
println("开始创建table")
val table = conn.getTable(TableName.valueOf(tableName))
println("创建结束")
// 获取表
put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(column), Bytes.toBytes(value))
table.put(put)
System.out.println("add data Success!")
}

@throws[IOException]
def get(rowKey: String, tableName: String): Unit = {
val get = new Get(Bytes.toBytes(rowKey))
val table = conn.getTable(TableName.valueOf(tableName))
val result: Result = table.get(get)
val it = result.listCells().iterator()
while (it.hasNext) {
val cell: Cell = it.next()
cell.getValueArray
println("value:" + Bytes.toString(cell.getValueArray, cell.getValueOffset, cell.getValueLength))
println("column familly:" + Bytes.toString(cell.getValueArray, cell.getFamilyOffset, cell.getFamilyLength))
println("Qualifier:" + Bytes.toString(cell.getValueArray, cell.getQualifierOffset, cell.getQualifierLength))
}
}

def scan(tableName: String): Unit = {
val scan = new Scan()
var rs: ResultScanner = null
val table = conn.getTable(TableName.valueOf(tableName))
try {
rs = table.getScanner(scan)
val it = rs.iterator()
while (it.hasNext) {
val cellIt = it.next().listCells().iterator()
while (cellIt.hasNext) {
val kv = cellIt.next()
println("value:" + Bytes.toString(kv.getValueArray, kv.getValueOffset, kv.getValueLength))
println("column familly:" + Bytes.toString(kv.getValueArray, kv.getFamilyOffset, kv.getFamilyLength))
println("Qualifier:" + Bytes.toString(kv.getValueArray, kv.getQualifierOffset, kv.getQualifierLength))
System.out.println("timestamp:" + kv.getTimestamp)
System.out.println("-------------------------------------------")
}

}
} finally rs.close()

}

def createTable(tableName: String): Unit = {
val admin = conn.getAdmin.asInstanceOf[HBaseAdmin]

val tn = TableName.valueOf(tableName)
val descriptor: HTableDescriptor = new HTableDescriptor(tn)
val cf = new HColumnDescriptor("cf")
descriptor.addFamily(cf)
admin.createTable(descriptor)
admin.close()
}

def del(tableName: String, rowkey: String): Unit = {
val table = conn.getTable(TableName.valueOf(tableName))
val del = new Delete(Bytes.toBytes(rowkey))
table.delete(del)

table.close()
println("删除成功")
}

/**
* 根据时间戳,删除数据
* @param tableName
* @param minTime
* @param maxTime
*/
def deleteTimeRange(tableName: String, minTime: Long, maxTime: Long) {

var table = conn.getTable(TableName.valueOf(tableName))
try {
val scan = new Scan()
scan.setTimeRange(minTime, maxTime)

val rs = table.getScanner(scan)

val list = getDeleteList(rs)
if (list.size() > 0) {
table.delete(list)
}
} catch {
case e: Exception => e.printStackTrace()
} finally {
table.close()
}
}

def getDeleteList(rs: ResultScanner): util.List[Delete] = {

val list = new util.ArrayList[Delete]()
try {

for (r: Result <- rs) {
val d = new Delete(r.getRow())
list.add(d)
}
} finally {
rs.close()
}
list
}

}

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/