文档章节

Elasticsearch 5.5 入门必会之Java client(二)

卡尔码农
 卡尔码农
发布于 2017/09/04 15:04
字数 1893
阅读 3367
收藏 61

前言

  • 由于本人一直从事Java方面研发,对Java也是尤其热爱,ES官方提供了Java的两种访问API的方式如下,当然,我选择了Java API方式,因此我也开始了API踩坑之路(因为这个SDK文档看起来让人头痛,但是当我一步步理解深入的时候也发现挺简单的):
  • Java API [5.5] — other versions
  • Java REST Client [5.5] — other versions

      注(es官方api文档):https://www.elastic.co/guide/en/elasticsearch/client/index.html

  • 相关文章:

         Elasticsearch 5.5 入门必会(一)

         Elasticsearch 5.5 SQL语句转Java Client 及相关注意事项(三)

一、Java项目构建

  • 客户端调用Maven依赖,客户端我配置的是slf4j+log4j2,配置太多就不贴上来了
    <dependency>
    	<groupId>org.elasticsearch</groupId>
    	<artifactId>elasticsearch</artifactId>
    	<version>5.5.1</version>
    </dependency>
    <!-- 这个一定要引入,这是使用transport的jar -->
    <dependency>
    	<groupId>org.elasticsearch.client</groupId>
    	<artifactId>transport</artifactId>
    	<version>5.5.1</version>
    </dependency>
    <!-- es 的jar 对guava有依赖 -->
    <dependency>
    	<groupId>com.google.guava</groupId>
    	<artifactId>guava</artifactId>
    	<version>18.0</version>
    </dependency>

     

  • Java连接ES 节点代码如下
    
    Settings settings = Settings.builder()
                        //集群名称
    					.put("cluster.name", "onesearch")
                        //自动嗅探
    					.put("client.transport.sniff", true)
    					.put("discovery.type", "zen")
    					.put("discovery.zen.minimum_master_nodes", 1)
    					.put("discovery.zen.ping_timeout", "500ms")
    					.put("discovery.initial_state_timeout", "500ms")
    					.build();
    Client client = new PreBuiltTransportClient(settings)
    					.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ip), 9300));

    启动程序不报错就代表您已经成功和ES建立连接。

 二、Java客户端操作索引数据

  • 入门时期看官方文档心中会冒出“麻买皮”三个字,因为官方文档有时候给你一个冷不丁的例子,有时候干脆贴除了Rest方式的JSON代码,万只草泥马没有在奔跑,正在疯狂吃草,Java API方式实际上也是拼装了JSON字符串,然后通过netty去和ES通信,对比http的方式访问的话SDK可以自动嗅探节点还是不错的,一个节点挂了还能用另外一个,http因为制定了单个IP,所以没有这个优势

实例一:我怎样写数据到ES里面去

/**
* ES的基本类型可以去官网查看
* 如果您使用map的方式去写入数据并且创建索引,es会自动根据map的value数据类型来自动转换
* 比如age是int,es里面使用有integer,不赘述
* 使用map有个大缺陷(除非自己封装对象保存),当你保存java.util.Date类型进去的时候ES会全部转成UTC来保存
* 这个只能通过后面的api方式定义索引field的一些属性来指定才行
**/
@Test
public void createData() {
	Map<String, Object> map = new HashMap<String, Object>();
	// map.put("name", "Smith Wang");
	map.put("name", "Smith Chen");
	// map.put("age", 20);
	map.put("age", 5);
	// map.put("interests", new String[]{"sports","film"});
	map.put("interests", new String[] { "reading", "film" });
	// map.put("about", "I love to go rock music");
	map.put("about", "I love to go rock climbing");

	IndexResponse response = client.prepareIndex("megacorp", "employee", UUID.randomUUID().toString())
			.setSource(map).get();
	System.out.println("写入数据结果=" + response.status().getStatus() + "!id=" + response.getId());
}
  •  说明:prepareIndex第一个参数是 index(索引) ,第二个是type(类型),第三个是记录ID(不推荐使用UUID,后面会说)

 

    然后在基本查询里面就可以查到你刚刚插入的数据了

---------------------------------------------------------------------------------------------------

 

实例二:我怎样从ES中根据字段来查询数据(其实我的实例都是根据Elasticsearch权威指南上翻译过来的,因为书中全部都是rest方式,不是Java api方式)

/**
 * match使用,会被分词查询
 */
@Test
public void match() {
	SearchRequestBuilder requestBuilder = client.prepareSearch("megacorp").setTypes("employee")
			.setQuery(QueryBuilders.matchQuery("about", "rock climbing"));
	System.out.println(requestBuilder.toString());

	SearchResponse response = requestBuilder.execute().actionGet();

	System.out.println(response.status());
	if (response.status().getStatus() == 200) {
		for (SearchHit hits : response.getHits().getHits()) {
			System.out.println(hits.getSourceAsString());
		}
	}
}

OK,这些都是最基本的操作了!看似没有难度

 

三、通过Java API编写复杂的查询语句

  • match phrase短语精准匹配
	/**
	 * matchphrase使用,短语精准匹配
     * 不使用matchPhraseQuery会导致 rock climbing被拆分查询
	 */
	@Test
	public void matchPhrase() {
		SearchRequestBuilder requestBuilder = client.prepareSearch("megacorp").setTypes("employee")
				.setQuery(QueryBuilders.matchPhraseQuery("about", "rock climbing"));
		System.out.println(requestBuilder.toString());

		SearchResponse response = requestBuilder.execute().actionGet();
		System.out.println(response.status());
		if (response.status().getStatus() == 200) {
			for (SearchHit hits : response.getHits().getHits()) {
				System.out.println(hits.getSourceAsString());
			}
		}
	}
  • 高亮显示
@Test
public void highlight() {
	HighlightBuilder highlightBuilder = new HighlightBuilder();
	// highlightBuilder.preTags(FragmentSettings.prefix);//设置前缀
	// highlightBuilder.postTags(FragmentSettings.subfix);//设置后缀
	highlightBuilder.field("about");
	// highlightBuilder.fragmenter(FragmentSettings.SPAN)
	// .fragmentSize(FragmentSettings.HIGHLIGHT_MAX_WORDS).numOfFragments(5);
	SearchRequestBuilder requestBuilder = client.prepareSearch("megacorp").setTypes("employee")
			.setQuery(QueryBuilders.matchPhraseQuery("about", "rock climbing")).highlighter(highlightBuilder);
	System.out.println(requestBuilder.toString());

	SearchResponse response = requestBuilder.execute().actionGet();

	System.out.println(response.status());
	if (response.status().getStatus() == 200) {
		for (SearchHit hits : response.getHits().getHits()) {
			System.out.println(hits.getSourceAsString());
			// 这里使用hight field来覆盖source里面的字段即可
			System.out.println(hits.getHighlightFields());
		}
	}

}
  • 关系型数据的GROUP BY 方式查询
@Test
public void aggregation() {
	SearchRequestBuilder searchBuilder = client.prepareSearch("megacorp").setTypes("employee")
			.addAggregation(AggregationBuilders.terms("by_interests").field("interests")
					.subAggregation(AggregationBuilders.terms("by_age").field("age")).size(10));
	System.out.println(searchBuilder.toString());
	SearchResponse response = searchBuilder.execute().actionGet();

	if (response.status().getStatus() == 200) {
		for (SearchHit hits : response.getHits().getHits()) {
			System.out.println(hits.getSourceAsString());
		}
	}
	StringTerms terms = response.getAggregations().get("by_interests");
	for (StringTerms.Bucket bucket : terms.getBuckets()) {
		System.out.println("-interest:" + bucket.getKey() + "," + bucket.getDocCount());
		if (bucket.getAggregations() != null && bucket.getAggregations().get("by_age") != null) {
			LongTerms ageTerms = bucket.getAggregations().get("by_age");
			for (LongTerms.Bucket bucket2 : ageTerms.getBuckets()) {
				System.out.println("--------by age:" + bucket2.getKey() + "," + bucket2.getDocCount());
			}
		}
	}
}
  • GROUP BY 的同时求平均值(求和等)
/**
	 * 聚合类+求平均年龄
     * 求和使用AggregationBuilders.sum
     * 注意AggregationBuilders.terms("by_interests") by_interests是分组的一个key,返回结果时你根据key反
     * 过来取值即可
	 */
	@Test
	public void aggregationAvg() {
		SearchRequestBuilder searchBuilder = client.prepareSearch("megacorp").setTypes("employee")
				.addAggregation(AggregationBuilders.terms("by_interests").field("interests")
						.subAggregation(AggregationBuilders.avg("avg_age").field("age")).size(10));
		System.out.println(searchBuilder.toString());
		SearchResponse response = searchBuilder.execute().actionGet();
		if (response.status().getStatus() == 200) {
			for (SearchHit hits : response.getHits().getHits()) {
				System.out.println(hits.getSourceAsString());
			}
		}

		StringTerms terms = response.getAggregations().get("by_interests");
		for (StringTerms.Bucket bucket : terms.getBuckets()) {
			System.out.println("-interest:" + bucket.getKey() + "," + bucket.getDocCount() + ",");
			InternalAvg agg = bucket.getAggregations().get("avg_age");
			System.out.println("---------avg age:" + agg.value() + ",count=" + agg.getValueAsString());
		}
	}

 

四、通过Java API进行索引操作

  • 下面是官方给出的创建索引,并且指定字段类型的操作,这里很“麻买皮”
	@Test
	public void createIndexInfo() {
		client.admin().indices().prepareCreate("megacorp")
				.setSettings(Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 1))
				.addMapping("employee",
						"{\n" + "  \"properties\": {\n" + "    \"age\": {\n" + "      \"type\": \"integer\"\n"
								+ "    },\n" + "    \"name\": {\n" + "      \"type\": \"text\"\n" + "    },\n"
								+ "    \"interests\": {\n" + "      \"type\": \"text\",\n"
								+ "      \"fielddata\": true\n" + "    },\n" + "    \"about\": {\n"
								+ "      \"type\": \"text\"\n" + "    }\n" + "  }\n" + "}",
						XContentType.JSON)
				.get();
	}
  • 当然,官方也给出了一个比较优雅的解决方案(XContentBuilder),如下
XContentBuilder mapping = JsonXContent.contentBuilder()
.startObject()
	.startObject("productIndex")
		.startObject("properties")
			.startObject("title").field("type", "string").field("store", "yes").endObject()
			.startObject("description").field("type", "string").field("index", "not_analyzed").endObject()
			.startObject("price").field("type", "double").endObject()
			.startObject("onSale").field("type", "boolean").endObject()
			.startObject("type").field("type", "integer").endObject()
			.startObject("createDate").field("type", "date").endObject()
		.endObject()
	.endObject()
.endObject();


相当于: 
{
	{
		"productIndex":{
			"properties": {
				"title":{
					"type":"string",
					"store":"yes"
				}
			},
            ..
		}
	}
}

总的来说,这种解决方式会比拼接字符串好一点,不会感觉很low

  • 完整的API方式创建索引(这里麻烦凑合看下,因为我做了一个从关系数据库抽取数据写到ES的完整操作),看一下重点关注代码行即可,我其实做了XML相关的改造,将数据库字段映射成ES字段操作,您先关注简单的创建流程
@Test
	public void createIndexWithXML() throws Exception {
        //重点关注代码行
		IndicesExistsRequestBuilder indices = client.admin().indices().prepareExists("test");
		List<SqlMappingConfig> mappingList = ElasticXMLReader.getSearchInfoList();
		//重点关注代码行
		if(!indices.execute().actionGet().isExists()) {
            //重点关注代码行
			XContentBuilder builder = JsonXContent.contentBuilder();
			builder.startObject().startObject("properties");
			SqlMappingConfig mapping = mappingList.get(0);
			for(Column column : mapping.getSearchInfo().getColumns()) {
				builder.startObject(column.getAttriMap().get("index-column"));
					for(Entry<String, String> entry : column.getAttriMap().entrySet()) {
						if(!entry.getKey().equals("index-column") &&  !entry.getKey().equals("sql-column")) {
							builder.field(entry.getKey().equals("data-type")?"type":entry.getKey(), entry.getValue());
						}
					}
				builder.endObject();
			}
			builder.endObject().endObject();

            //重点关注代码行
			PutMappingRequest mappingRequest = Requests.putMappingRequest(mapping.getSearchInfo().getIndex()).type(mapping.getSearchInfo().getType());
			mappingRequest.source(builder);
			
            //重点关注代码行
			CreateIndexResponse response = client.admin().indices().prepareCreate(mapping.getSearchInfo().getIndex())
					.setSettings(Settings.builder().put("index.number_of_shards", 8).put("index.number_of_replicas", 1))
					.addMapping(mapping.getSearchInfo().getType(), mappingRequest.source(),XContentType.JSON).execute().actionGet();
			
			System.out.println(response.isAcknowledged());
		}
	}

 

最后

     很多人有洁癖,喜欢用纯SDK代码方式来操作API,我也踩了无数的坑,上面的代码都是我一步步试出来的,之前加了一个es的学习群,但是不知道是不是我问的问题太简单了,在里面问问题都没有人指导,后来很遗憾的退出了那个群。不过很感谢那个群,我学到了一个东西,就是Elasticsearch-sql工具,这个工具支持关系型数据库的语句转 es的查询参数,很方便! 通过生成的json参数,可以反过来照抄来写Java代码(虽然很别扭,但是已经很不错了)

     后面我会写一篇关于关系型数据库的查询语句 变成 ES Java代码的样例出来,还请关注

© 著作权归作者所有

卡尔码农
粉丝 89
博文 15
码字总数 19284
作品 0
常德
其他
私信 提问
加载中

评论(5)

卡尔码农
卡尔码农 博主

引用来自“nuanfeng_f”的评论

引用来自“天可汗1987”的评论

引用来自“nuanfeng_f”的评论

3天接触,写了一个企业级的应用,集成了推荐这块

@nuanfeng_f 估计效果也一般

回复@天可汗1987 : 还行吧,百万的请求跟玩儿似的

qps是与生具来的,他估计说的是推荐这块
nuanfeng_f
nuanfeng_f

引用来自“天可汗1987”的评论

引用来自“nuanfeng_f”的评论

3天接触,写了一个企业级的应用,集成了推荐这块

@nuanfeng_f 估计效果也一般

回复@天可汗1987 : 还行吧,百万的请求跟玩儿似的
天可汗1987

引用来自“nuanfeng_f”的评论

3天接触,写了一个企业级的应用,集成了推荐这块

@nuanfeng_f 估计效果也一般
卡尔码农
卡尔码农 博主

引用来自“nuanfeng_f”的评论

3天接触,写了一个企业级的应用,集成了推荐这块

这么牛
nuanfeng_f
nuanfeng_f
3天接触,写了一个企业级的应用,集成了推荐这块
elasticsearch和mysql的数据同步采用哪种方案合适。

最近公司在使用elasticsearch,使用的是6.5版本的。其中有一个需求就是需要把数据库已有的数据同步到elasticsearch中来,调研了几种方案。 logstash,elasticsearch-jdbc,自己实现。 暂时采...

lanceli
03/18
0
0
在SpringBoot中使用Elasticsearch

一、SpringBoot模版方式接入(不建议) 其实一开始是准备用SpringBoot的模版来直接接入使用的,也就是以下这样的接入方式,也是网上大家都这么说的使用方式。 但是后面看java api的官方文档 De...

C6C
06/04
0
0
ElasticSearch Client详解

从本文开始,将与大家进入到Elasticsearch的精妙世界中来,基于当前最新的6.4.x版本。 本文将重点探讨ElasticSearch Client的相关知识,重点关注TransportClient与Rest Client。Elasticsear...

丁威
03/10
0
0
Elasticsearch入门实践

一. 系统环境 操作系统:CentOS release 6.8 (Final) ES版本:6.1.1 二. 安装 先确认安装了Java运行时环境: 解压ES压缩包: 三. 启动 1. 启动ES单节点 当然,对于在后台以守护进程模式运行的...

哲别0
2018/06/06
0
0
Grafana、elasticsearch、kafka、logstash和pinpoint结合

一、Grafana 1)下载安装 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.2.0-1.x8664.rpm sudo yum localinstall grafana-4.2.0-1.x86_64.rpm 2)启动 serv......

半船水
2017/10/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

spring mvc主流程源码阅读(剖析)

第一步,通过web.xml的配置可以知道,用户访问url第一次先走到DispatchServlet,(默认你学过基本的java的Servlet开发) <servlet><servlet-name>springServlet</servlet-name><serv......

小海bug
22分钟前
2
0
vmstat命令详解

https://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html

流光韶逝
57分钟前
1
0
如何理解算法时间复杂度的表示

先从O(1) 来说,理论上哈希表就是O(1)。因为哈希表是通过哈希函数来映射的,所以拿到一个关键 字,用哈希函数转换一下,就可以直接从表中取出对应的值。和现存数据有多少毫无关系,故而每次执...

yky20190625
今天
7
0
分布式架构 实现分布式锁的常见方式

一、我们为什么需要分布式锁? 在单机时代,虽然不需要分布式锁,但也面临过类似的问题,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制...

太猪-YJ
今天
9
0
GitLab Docker 安装记录

安装环境 环境Centos7.4 64 1.拉取镜像文件 docker pull gitlab/gitlab-ce:latest 2.docker 安装 git.zddts.com 为访问域名或换成可以访问的IP docker run -d --hostname git.***.com -p ......

侠者圣
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部