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

Stella981
• 阅读 1081

前言

  • 由于本人一直从事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,后面会说)

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

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

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

实例二:我怎样从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 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代码的样例出来,还请关注

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java爬虫之JSoup使用教程
title:Java爬虫之JSoup使用教程date:201812248:00:000800update:201812248:00:000800author:mecover:https://imgblog.csdnimg.cn/20181224144920712(https://www.oschin
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这