Elasticsearch:Java 运用示例
在今天的文章中,我们来介绍如何使用Java来访问Elasticsearch。
首先,我们必须在我们的系统中安装Elasticsearch。
Maven 配置
针对Java的开发,我们必须在pom.xml中配置相应的Elasticsearch的信息。Mavev dependency定义如下:
        <dependency>
          <groupId>org.elasticsearch</groupId>
          <artifactId>elasticsearch</artifactId>
          <version>7.3.1</version>
        </dependency>
这也是目前截止最新的Elasticsearch的版本。您可以随时使用之前提供的链接查看Maven Central托管的最新版本。
完成数据库的查询
建立一个简单的model
    package com.javacodegeeks.example;
    public class Person {
        private String personId;
        private String name;
        private String number;
        public String getNumber() {
            return number;
        }
        public void setNumber(String number) {
            this.number = number;
        }
        public String getPersonId() {
            return personId;
        }
        public void setPersonId(String personId) {
            this.personId = personId;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return String.format("Person{personId='%s', name='%s', number='%s}", personId, name, number);
        }
    }
在这里,我们定义了一个简单的Person Model。
定义连接参数
我们将使用默认连接参数与Elasticsearch建立连接。 默认情况下,ES使用两个端口:9200和9201
        private static final String HOST = "localhost";
        private static final int PORT_ONE = 9200;
        private static final int PORT_TWO = 9201;
        private static final String SCHEME = "http";
        private static RestHighLevelClient restHighLevelClient;
        private static ObjectMapper objectMapper = new ObjectMapper();
        private static final String INDEX = "persondata";
        private static final String TYPE = "_doc";
这里我们定义了一个叫做persondata的index,它的type是_doc。在最新的版本中,每个index只支持一个type。
如上面参数中所述,Elasticsearch使用两个端口9200和9201.第一个端口9200由Elasticsearch查询服务器使用,我们可以使用它通过RESTful API直接查询数据库。 第二个端口9201由REST服务器使用,外部客户端可以使用该端口连接并执行操作。
建立一个连接
我们将创建一个与Elasticsearch数据库建立连接的方法。 在建立与数据库的连接时,我们必须提供两个端口,因为只有这样,我们的应用程序才能连接到Elasticsearch服务器,我们将能够执行数据库操作。 以下是建立连接的代码。
        private static synchronized RestHighLevelClient makeConnection() {
            if(restHighLevelClient == null) {
                restHighLevelClient = new RestHighLevelClient(
                        RestClient.builder(
                                new HttpHost(HOST, PORT_ONE, SCHEME),
                                new HttpHost(HOST, PORT_TWO, SCHEME)));
            }
            return restHighLevelClient;
        }
在这里,我们建立一个RestHighLevelClient的实例。具体的参数,可以参官方文档 Java High Level REST Client (https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high.html)。
请注意,我们在此处实现了Singleton Design模式,因此不会为ES创建多个连接,从而节省大量内存。
由于存在RestHighLevelClient,与Elasticsearch的连接是线程安全的。 初始化此连接的最佳时间是应用程序请求或向客户端发出第一个请求时。 初始化此连接客户端后,可以使用它来执行任何支持的API。
关掉一个连接
就像在早期版本的Elasticsearch中一样,我们使用TransportClient,一旦完成查询就关闭它,一旦数据库交互完成RestHighLevelClient,也需要关闭连接。 以下是如何做到这一点:
        private static synchronized void closeConnection() throws IOException {
            restHighLevelClient.close();
            restHighLevelClient = null;
        }
我们还为RestHighLevelClient对象分配了null,以便Singleton模式可以保持一致。
插入一个文档
我们可以通过将键和值转换为HashMap将数据插入数据库。 ES数据库仅接受HashMap形式的值。 让我们看看如何实现这一目标的代码片段:
       private static Person insertPerson(Person person) {
            person.setPersonId(UUID.randomUUID().toString());
            Map<String, Object> dataMap = new HashMap<String, Object>();
            dataMap.put("name", person.getName());
            dataMap.put("number", person.getNumber());
            IndexRequest indexRequest = new IndexRequest(INDEX)
                    .id(person.getPersonId()).source(dataMap);
            try {
                IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            } catch(ElasticsearchException e) {
                e.getDetailedMessage();
            } catch (java.io.IOException ex){
                ex.getLocalizedMessage();
            }
            /*
            // The following is another way to do it
            // More information https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-document-index.html
            String id = UUID.randomUUID().toString();
            person.setPersonId(id);
            IndexRequest request = new IndexRequest(INDEX);
            request.id(id);
            String jsonString = "{" +
                    "\"name\":" + "\"" + person.getName() + "\"" +
                    "}";
            System.out.println("jsonString: " + jsonString);
            request.source(jsonString, XContentType.JSON);
            try {
                IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
            } catch(ElasticsearchException e) {
                e.getDetailedMessage();
            } catch (java.io.IOException ex){
                ex.getLocalizedMessage();
            }
             */
            return person;
        }
就像上面代码中注释的那样。注释的代码的那一部分是另外一种方法。大家可以参照链接(https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-document-index.html)获得更多的信息。
上面,我们使用Java的UUID类来创建对象的唯一标识符。 这样,我们就可以控制对象标识符的制作方式。我们其实也可以固定一个id去写。如果是这样的话,运行多次,只会更新之前的数据,并且version会自动每次运行后增加1。
请求上面存入的文档
完成将数据插入数据库后,我们可以通过向Elasticsearch数据库服务器发出GET请求来确认操作。 让我们看看如何完成此操作的代码片段:
 
       private static Person getPersonById(String id){
            GetRequest getPersonRequest = new GetRequest(INDEX, id);
            GetResponse getResponse = null;
            try {
                getResponse = restHighLevelClient.get(getPersonRequest, RequestOptions.DEFAULT);
            } catch (java.io.IOException e){
                e.getLocalizedMessage();
            }
            return getResponse != null ?
                    objectMapper.convertValue(getResponse.getSourceAsMap(), Person.class) : null;
        }
在这里,我们根据上面返回来得id来进行query,并返回数据。
在这个查询中,我们只提供了可以识别它的对象的主要信息,即索引,和它的唯一标识符id。 此外,我们得到的实际上是一个值的映射。
更新文档
我们可以通过首先使用其索引,类型和唯一标识符来标识资源,从而轻松地向Elasticsearch发出更新请求。 然后我们可以使用新的HashMap对象来更新Object中的任意数量的值。 这是一个示例代码段:
       private static Person updatePersonById(String id, Person person){
            UpdateRequest updateRequest = new UpdateRequest(INDEX, id)
                    .fetchSource(true);    // Fetch Object after its update
            try {
                String personJson = objectMapper.writeValueAsString(person);
                updateRequest.doc(personJson, XContentType.JSON);
                UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
                return objectMapper.convertValue(updateResponse.getGetResult().sourceAsMap(), Person.class);
            }catch (JsonProcessingException e){
                e.getMessage();
            } catch (java.io.IOException e){
                e.getLocalizedMessage();
            }
            System.out.println("Unable to update person");
            return null;
        }
删除文档
最后,我们可以通过简单地使用其索引,类型和唯一标识符来标识资源来删除数据。 让我们看一下如何完成此操作的代码片段
        private static void deletePersonById(String id) {
            DeleteRequest deleteRequest = new DeleteRequest(INDEX, TYPE, id);
            try {
                DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            } catch (java.io.IOException e) {
                e.getLocalizedMessage();
            }
        }
我们根据传入的id来删除相应的文档。当然我们也可以做查询删除。
运行我们的应用
让我们通过执行上面提到的所有操作来尝试我们的应用程序。 由于这是一个普通的Java应用程序,我们将调用这些方法中的每一个并打印操作结果:
       public static void main(String[] args) throws IOException {
            makeConnection();
            Person person = new Person();
            person.setName("张三");
            System.out.println("Inserting a new Person with name " + person.getName());
            person.setNumber("111111");
            person = insertPerson(person);
            System.out.println("Person inserted --> " + person);
            person = new Person();
            person.setName("姚明");
            System.out.println("Inserting a new Person with name " + person.getName());
            person.setNumber("222222");
            person = insertPerson(person);
            System.out.println("Person inserted --> " + person);
            person.setName("李四");
            System.out.println("Changing name to " + person.getName());
            updatePersonById(person.getPersonId(), person);
            System.out.println("Person updated  --> " + person);
            System.out.println("Searching for all documents");
            SearchResponse response = searchAll();
            System.out.println(response);
            System.out.println("Searching for a term");
            response = searchTerm();
            System.out.println(response);
            System.out.println("Match a query");
            response = matchQuery();
            System.out.println(response);
            System.out.println("Getting 李四");
            Person personFromDB = getPersonById(person.getPersonId());
            System.out.println("Person from DB  --> " + personFromDB);
            System.out.println("Deleting " + person.getName());
            deletePersonById(personFromDB.getPersonId());
            System.out.println("Person " + person.getName() + " deleted!");
            closeConnection();
        }
运行的结果如下:
    Inserting a new Person with name 张三
    Person inserted --> Person{personId='33f4162e-0a68-4e66-8717-851516272185', name='张三', number='111111}
    Inserting a new Person with name 姚明
    Person inserted --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='姚明', number='222222}
    Changing name to 李四
    Person updated  --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='李四', number='222222}
    Searching for all documents
    {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":4,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":1.0,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":1.0,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":1.0,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"468dabe4-8f50-4667-a165-9ce6e015cb76","_score":1.0,"_source":{"number":"222222","name":"李四","personId":"468dabe4-8f50-4667-a165-9ce6e015cb76"}}]}}
    Searching for a term
    {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"relation":"eq"},"max_score":0.9444616,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":0.9444616,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":0.9444616,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":0.9444616,"_source":{"number":"111111","name":"张三"}}]}}
    Match a query
    {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"relation":"eq"},"max_score":1.8889232,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":1.8889232,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":1.8889232,"_source":{"number":"111111","name":"张三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":1.8889232,"_source":{"number":"111111","name":"张三"}}]}}
    Getting 李四
    Person from DB  --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='李四', number='222222}
整个项目的源码可以在地址找到:https://github.com/liu-xiao-guo/elastic-java
更多资料:
【1】使用RestHighLevelClient时单个索引速度很慢(https://discuss.elastic.co/t/resthighlevelclient/170293)
Elasticsearch:Java 运用示例的更多相关文章
- Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)
		
elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介.Java REST Client.Java Client.Spri ...
 - Elasticsearch 邻近查询示例
		
Elasticsearch 邻近查询示例(全切分分词) JAVA API方式: SpanNearQueryBuilder span = QueryBuilders.spanNearQuery(); s ...
 - Elasticsearch Java API深入详解
		
0.题记 之前Elasticsearch的应用比较多,但大多集中在关系型.非关系型数据库与Elasticsearch之间的同步.以上内容完成了Elasticsearch所需要的基础数据量的供给.但想要 ...
 - 正则表达式学习笔记(附:Java版示例代码)
		
具体学习推荐:正则表达式30分钟入门教程 . 除换行符以外的任意字符\w word,正常字符,可以当做变量名的,字母.数字.下划线.汉字\s space,空白符 ...
 - [搜索]ElasticSearch Java Api(一) -添加数据创建索引
		
转载:http://blog.csdn.net/napoay/article/details/51707023 ElasticSearch JAVA API官网文档:https://www.elast ...
 - Elasticsearch java api 基本搜索部分详解
		
文档是结合几个博客整理出来的,内容大部分为转载内容.在使用过程中,对一些疑问点进行了整理与解析. Elasticsearch java api 基本搜索部分详解 ElasticSearch 常用的查询 ...
 - Elasticsearch java api 常用查询方法QueryBuilder构造举例
		
转载:http://m.blog.csdn.net/u012546526/article/details/74184769 Elasticsearch java api 常用查询方法QueryBuil ...
 - Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI
		
目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...
 - Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries
		
目录 上篇回顾 Building Queries 匹配所有的查询 全文查询 Full Text Queries 什么是全文查询? Match 全文查询 API 列表 基于词项的查询 Term Term ...
 - State of the official Elasticsearch Java clients
		
Elasticsearch Java Clients | Elastic https://www.elastic.co/blog/state-of-the-official-elasticsearch ...
 
随机推荐
- Tapdata Cloud 版本上新 | 支持通知自配置,支持GP、MQ数据源,界面更友好!
			
Tapdata Cloud https://cloud.tapdata.net Tapdata Cloud 是国内首家异构数据库实时同步云平台,目前支持Oracle.MySQL.PG.SQL Serv ...
 - 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
			
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
 - 在 IDEA 里下个五子棋不过分吧?
			
大家好,我是二哥呀!今天给大家分享一个基于Netty的IDEA即时聊天插件,可以实现即时聊天.游戏对战(下棋). GitHub 地址:https://github.com/anlingyi/xecha ...
 - 弹性布局( display: flex;)
			
参考: https://www.cnblogs.com/hellocd/p/10443237.html
 - 2022-7-12  第五组 pan小堂  js
			
JavaScript Switch 语句 (熟悉掌握) 请使用 switch 语句来选择多个需被执行的代码块之一. 语法: switch(表达式){ case n: 代码块 break; case n ...
 - vscode无法调试python2.7版本
			
概述 好久没有用python2.7版本了,最近有个老的脚本要优化,但是发现vscode无法对脚本调试,特此记录下解决方法. 本地安装有python2和python3,开发过程中,vscode可以随时调 ...
 - 1000-ms-HashMap 线程安全安全问题
			
问题: HashMap是否是线程安全 详解 http://www.importnew.com/21396.html 有源码分析 和代码性能比较 CHM性能最好 HashMap不是线程安全的:Hasht ...
 - js入门基础
			
JavaScript语言介绍 JavaScript的历史 诞生于1995年,最初名字叫做Mocha,1995年9月改为LiveScript.Netscape公司与Sun公司(Java语言的发明者)达成 ...
 - C#/VB.NET 替换 PDF 文件上的现有图像
			
我们都知道对PDF文件进行修改和编辑不是一件容易的事.但有时当我们想用新的图像来替换PDF文件上的现有图像时,该怎么办呢?别担心,本文将向您展示如何在 C#/VB.NET 中替换 PDF 文件中的现有 ...
 - Mysql 实现数据库读写分离
			
Amoeba+Mysql实现数据库读写分离 一.Amoeba 是什么 Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发.座落与Client.DB Server(s)之间.对客户端透明. ...