在今天的文章中,我们来介绍如何使用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 运用示例的更多相关文章

  1. 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 ...

  2. Elasticsearch 邻近查询示例

    Elasticsearch 邻近查询示例(全切分分词) JAVA API方式: SpanNearQueryBuilder span = QueryBuilders.spanNearQuery(); s ...

  3. Elasticsearch Java API深入详解

    0.题记 之前Elasticsearch的应用比较多,但大多集中在关系型.非关系型数据库与Elasticsearch之间的同步.以上内容完成了Elasticsearch所需要的基础数据量的供给.但想要 ...

  4. 正则表达式学习笔记(附:Java版示例代码)

    具体学习推荐:正则表达式30分钟入门教程 .         除换行符以外的任意字符\w      word,正常字符,可以当做变量名的,字母.数字.下划线.汉字\s        space,空白符 ...

  5. [搜索]ElasticSearch Java Api(一) -添加数据创建索引

    转载:http://blog.csdn.net/napoay/article/details/51707023 ElasticSearch JAVA API官网文档:https://www.elast ...

  6. Elasticsearch java api 基本搜索部分详解

    文档是结合几个博客整理出来的,内容大部分为转载内容.在使用过程中,对一些疑问点进行了整理与解析. Elasticsearch java api 基本搜索部分详解 ElasticSearch 常用的查询 ...

  7. Elasticsearch java api 常用查询方法QueryBuilder构造举例

    转载:http://m.blog.csdn.net/u012546526/article/details/74184769 Elasticsearch java api 常用查询方法QueryBuil ...

  8. Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI

    目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...

  9. Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries

    目录 上篇回顾 Building Queries 匹配所有的查询 全文查询 Full Text Queries 什么是全文查询? Match 全文查询 API 列表 基于词项的查询 Term Term ...

  10. State of the official Elasticsearch Java clients

    Elasticsearch Java Clients | Elastic https://www.elastic.co/blog/state-of-the-official-elasticsearch ...

随机推荐

  1. Python 中生成器的原理

    生成器的使用 在 Python 中,如果一个函数定义的内部使用了 yield 关键字,那么在执行函数的时候返回的是一个生成器,而不是常规函数的返回值. 我们先来看一个常规函数的定义,下面的函数 f() ...

  2. 【cartographer_ros】六: 发布和订阅路标landmark信息

    上一节介绍了陀螺仪Imu传感数据的订阅和发布. 本节会介绍路标Landmark数据的发布和订阅.Landmark在cartographer中作为定位的修正补充,避免定位丢失. 这里着重解释一下Land ...

  3. 分库分表真的适合你的系统吗?聊聊分库分表和NewSQL如何选择

    曾几何时,"并发高就分库,数据大就分表"已经成了处理 MySQL 数据增长问题的圣经. 面试官喜欢问,博主喜欢写,候选人也喜欢背,似乎已经形成了一个闭环. 但你有没有思考过,分库分 ...

  4. LDAP+Gitea统一认证Git服务器账户管理openLdap和微软的ad

    很多时候我们需要管理多个内容管理系统,比如Jira.Jenkins.GitEA/Gitlab等等各种管理系统,我们需要每一套管理系统每个人都管理一套密码,每套系统每套密码简直是一种灾难,于是LDAP可 ...

  5. ERROR .web.servlet.DispatcherServlet - Context initialization failed

    自己创建了一个SSM 项目,使用maven的tomcat7 运行报错 ERROR .web.servlet.DispatcherServlet - Context initialization fai ...

  6. 博客从 CloudBase 迁移至云主机

    迁移起因 原来的博客 其实从很久以前就想要写博客,但总是断断续续的,一直都没有认真地开始. 最终,决定使用静态博客工具作为自己博客的承载体.在多种工具的比较下,最终选择了 Hugo 并部署到 Gith ...

  7. ETL工具 Flume (一)

    分布式日志采集系统Flume学习 一.Flume架构 1.1 Hadoop业务开发流程 1.2 Flume概述 flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统. 支持在日志系统 ...

  8. SPFA算法(SLF优化)2022.7.8更新

    SPFA可能会被卡掉,能用dijkstra就别用SPFA,代码较长,但我已尽力做到解释,请耐心看下去,存储为邻接表存储. #include<bits/stdc++.h> #define i ...

  9. 用VS Code搞Qt6:编译源代码与基本配置

    先说明一下,本水文老周仅讨论新版的 Qt 6,旧版的 Qt 不讨论. 尽管 Qt 有自己的开发环境,但老周必须说句不装逼的话:真的不好用.说起写代码,当然了,用记事本也能写.但是,有个高逼格的工具,写 ...

  10. MD5,Des,RSA加密解密

    一.加密和解密 下面先熟悉几个概念 1>对称加密:加密的key和解密的key是同一个 但是如何确保密钥安全地进行传递?秘钥的安全是一个问题 2>非对称加密:加密点的key和解密的key不是 ...