Elasticsearch 是一种实时分布式和开源的全文搜索和分析引擎。它是基于文档的搜索平台,具有快速搜索功能。它针对大海捞针式的搜索进行了优化,重点不在于一致性或原子性。
在本博客中,我将介绍如何下载Elasticsearch并进行设置。此外,如何使用 Spring Boot 和 Spring Data ElasticSearch 项目与Elasticsearch 引擎集成 。
首先,安装和设置elasticsearch引擎。
现在,我们将开发一个Spring Boot应用程序,它将展示 ElasticsearchTemplate 和 ElasticsearchRepository 访问Elasticsearch引擎的方式并进行CRUD操作。在开发应用程序之前,让我们首先了解 ElasticsearchTemplate 和 ElasticsearchRepository的 工作原理。
ElasticsearchTemplate - 它是一个实现ElasticsearchOperations的Template类 。 它比ElasticsearchRepository更强大,因为它可以做的不仅仅是CRUD操作。它具有创建,删除索引,批量上传的操作。它也可以进行聚合搜索。
ElasticsearchRepository - 如果我们定义一个扩展ElasticsearchRepository的接口 , 它由Spring数据Elasticsearch提供,它将自动为该Document提供CRUD操作。例如,通过扩展ElasticsearchRepository,UserRepository接口在下面定义了“ User ”文档。现在可以在用户文档上完成所有查找,保存,删除,更新默认操作。
@Repository <b>public</b> <b>interface</b> UserRepository <b>extends</b> ElasticsearchRepository<User, String> { }
它扩展了ElasticsearchCrudRepository,最终扩展了Repository接口。此存储库接口是Spring数据的标准功能。无需提供此接口的实现。您也可以使用@Query 注释编写自定义查询。
Maven配置:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
配置application.properties ,ElasticsearchTemplate 和 ElasticsearchRepository用这个配置来连接引擎。我使用了诸如集群节点之类的传输客户端属性和索引名称来连接elasticsearch引擎。
#application.properties # Local Elasticsearch config spring.data.elasticsearch.repositories.enabled=<b>true</b> spring.data.elasticsearch.cluster-nodes=localhost:9300 spring.data.elasticsearch.cluster-name=elasticsearch elasticsearch.index.name=my_index elasticsearch.user.type=user # App config server.port=8102 spring.application.name=BootElastic
Mappings
在Elasticsearch中, Index 就像RDBMS中的DB, Mappings / Type 类似于RDBMS中的表。 Document 是属于某种类型并位于索引中的字段的集合。Spring数据提供了像@ Document 这样的注释来创建文档。在这里,我们将User定义为索引为“ my_index ”并键入“ user ” 的文档。
@Document(indexName = <font>"my_index"</font><font>, type = </font><font>"user"</font><font>) <b>public</b> <b>class</b> User { @Id <b>private</b> String userId; <b>private</b> String name; <b>private</b> Date creationDate = <b>new</b> Date(); <b>private</b> Map<String, String> userSettings = <b>new</b> HashMap<>(); </font><font><i>//getter and setters </i></font><font> } </font>
控制器
第一个控制器是 UserController。它将使用 UserDAOImpl 让 ElasticserachTemplate 与Elasticsearch Engine 交互 。
@RestController <b>public</b> <b>class</b> UserController { @Autowired <b>private</b> UserDAO userDAO; @RequestMapping(<font>"/all"</font><font>) <b>public</b> List<User> getAllUsers() { <b>return</b> userDAO.getAllUsers(); } @RequestMapping(value = </font><font>"/new"</font><font>, method = RequestMethod.POST) <b>public</b> User addUsers(@RequestBody User user) { userDAO.addNewUser(user); <b>return</b> user; } --- Other methods } </font>
UserDAOImpl - 此类初始化elasticsearchtemplate并使用queryForList方法检索数据。
@Repository <b>public</b> <b>class</b> UserDAOImpl implements UserDAO { <b>private</b> <b>final</b> Logger LOG = LoggerFactory.getLogger(getClass()); @Value(<font>"${elasticsearch.index.name}"</font><font>) <b>private</b> String indexName; @Value(</font><font>"${elasticsearch.user.type}"</font><font>) <b>private</b> String userTypeName; @Autowired <b>private</b> ElasticsearchTemplate esTemplate; @Override <b>public</b> List<User> getAllUsers() { SearchQuery getAllQuery = <b>new</b> NativeSearchQueryBuilder() .withQuery(matchAllQuery()).build(); <b>return</b> esTemplate.queryForList(getAllQuery, User.<b>class</b>); } </font><font><i>// Other methods</i></font><font> } </font>
另一个Controller是UserRepositoryConroller。这是使用UserRepository与elasticsearch引擎进行交互。
@RestController @RequestMapping(<font>"/repo"</font><font>) <b>public</b> <b>class</b> UserRepositoryController { @Autowired <b>private</b> UserRepository userRepository; @RequestMapping(</font><font>"/all"</font><font>) <b>public</b> List<User> getAllUsers() { List<User> users = <b>new</b> ArrayList<>(); userRepository.findAll().forEach(users::add); <b>return</b> users; } </font><font><i>//Other methods</i></font><font> } </font>
此Repository类扩展了ElasticsearchRepository类,该类在内部扩展了 ElasticsearchCrudRepository - > PagingAndSortingRepository
@Repository <b>public</b> <b>interface</b> UserRepository <b>extends</b> ElasticsearchRepository<User, String> { }
你可以在github链接找到完整的代码 - https://github.com/RajeshBhojwani/spring-boot-elasticsearch.git
构建应用程序
可以使用Maven命令构建应用程序。
mvn clean install
将构建代码并创建 elasticsearch-0.0.1-SNAPSHOT.jar 文件。
运行该应用程序
java -jar target/elasticsearch-0.0.1-SNAPSHOT.jar
将启动该应用程序。应用程序将侦听application.properties 文件中定义的 端口 8102 。
测试应用程序 -
测试 使用ElasticsearchTemplate的UserController 流程。
第1步 - 添加新用户。使用此REST API URL添加新用户 http://localhost:8102/new
在Request正文中添加Json数据。
{ <font>"name"</font><font>: </font><font>"Sumit"</font><font>, </font><font>"userSettings"</font><font>: { </font><font>"gender"</font><font> : </font><font>"male"</font><font>, </font><font>"occupation"</font><font> : </font><font>"CA"</font><font>, </font><font>"hobby"</font><font> : </font><font>"chess"</font><font> } } </font>
第2步 - 检查响应。您将看到使用userId生成的新用户,该文档是此文档的唯一ID。输出如下:
{ <font>"userId"</font><font>: </font><font>"AWdj-3KcTJbZRlQtLZfO"</font><font>, </font><font>"name"</font><font>: </font><font>"Sumit"</font><font>, </font><font>"creationDate"</font><font>: 1543570682521, </font><font>"userSettings"</font><font>: { </font><font>"gender"</font><font>: </font><font>"male"</font><font>, </font><font>"occupation"</font><font>: </font><font>"CA"</font><font>, </font><font>"hobby"</font><font>: </font><font>"chess"</font><font> } } </font>
第3步 - 检索所有用户。使用 http://localhost:8102/all
{ <font>"userId"</font><font>: </font><font>"AWdj-3KcTJbZRlQtLZfO"</font><font>, </font><font>"name"</font><font>: </font><font>"Sumit"</font><font>, </font><font>"creationDate"</font><font>: 1543570682521, </font><font>"userSettings"</font><font>: { </font><font>"gender"</font><font>: </font><font>"male"</font><font>, </font><font>"occupation"</font><font>: </font><font>"CA"</font><font>, </font><font>"hobby"</font><font>: </font><font>"chess"</font><font> } }, { </font><font>"userId"</font><font>: </font><font>"AWdZuKFRgzULDLBu_Y0c"</font><font>, </font><font>"name"</font><font>: </font><font>"Suresh"</font><font>, </font><font>"creationDate"</font><font>: 1543398531296, </font><font>"userSettings"</font><font>: {} } </font>
测试 使用ElasticsearchRepository的UserRepositoryController 流。
第1步 - 添加新用户。使用此REST API URL添加新用户 http://localhost:8102/repo/new
像我们在之前的测试用例中那样在Request体中添加Json数据。
第2步 - 检查响应。您将看到使用userId生成的新用户,该文档是此文档的唯一ID。
Transport 客户端库
如何使用传输客户端库与最新版本的Elasticsearch引擎进行交互?我们可以直接从代码中调用Elasticsearch的REST API进行CRUD,也可以使用Elasticsearch提供的传输Transport客户端。
Maven依赖:需要Elasticsearch,一个传输客户端和log4j jar。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>5.0.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.7</version> </dependency> </dependencies>
配置:
由于我们将使用传输客户端连接到Elasticsearch引擎,因此我们需要为引擎的群集节点提供URL路径。所以我已将属性放在application.properties文件中,用于URL 的主机和端口。
# Local Elasticsearch config elasticsearch.host=localhost elasticsearch.port=9300 # App config server.port=8102 spring.application.name=BootElastic
创建一个名为的域类User。JSON输入将映射到此 User 对象。这将用于创建与索引和类型关联的用户文档。
<b>public</b> <b>class</b> User { <b>private</b> String userId; <b>private</b> String name; <b>private</b> Date creationDate = <b>new</b> Date(); <b>private</b> Map<String, String> userSettings = <b>new</b> HashMap<>(); -- getter/setter methods }
创建Java配置文件以创建连接到Elasticsearch集群节点的传输客户端。它还从application.properties文件配置的环境加载主机和端口的值 。
@Configuration <b>public</b> <b>class</b> config{ @Value(<font>"${elasticsearch.host:localhost}"</font><font>) <b>public</b> String host; @Value(</font><font>"${elasticsearch.port:9300}"</font><font>) <b>public</b> <b>int</b> port; <b>public</b> String getHost() { <b>return</b> host; } <b>public</b> <b>int</b> getPort() { <b>return</b> port; } @Bean <b>public</b> Client client(){ TransportClient client = <b>null</b>; <b>try</b>{ System.out.println(</font><font>"host:"</font><font>+ host+</font><font>"port:"</font><font>+port); client = <b>new</b> PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(<b>new</b> InetSocketTransportAddress(InetAddress.getByName(host), port)); } <b>catch</b> (UnknownHostException e) { e.printStackTrace(); } <b>return</b> client; } } </font>
UserController 创建以展示以下功能:
@Autowired Client client; @PostMapping(<font>"/create"</font><font>) <b>public</b> String create(@RequestBody User user) throws IOException { IndexResponse response = client.prepareIndex(</font><font>"users"</font><font>, </font><font>"employee"</font><font>, user.getUserId()) .setSource(jsonBuilder() .startObject() .field(</font><font>"name"</font><font>, user.getName()) .field(</font><font>"userSettings"</font><font>, user.getUserSettings()) .endObject() ) .get(); System.out.println(</font><font>"response id:"</font><font>+response.getId()); <b>return</b> response.getResult().toString(); } </font>
2.根据传递的“id”查看用户信息。客户端有一种 prepareGet() 方法可以根据索引,类型和id检索信息。它将以JSON格式返回用户信息。
@GetMapping(<font>"/view/{id}"</font><font>) <b>public</b> Map<String, Object> view(@PathVariable <b>final</b> String id) { GetResponse getResponse = client.prepareGet(</font><font>"users"</font><font>, </font><font>"employee"</font><font>, id).get(); <b>return</b> getResponse.getSource(); } </font>
3.根据字段名称查看用户信息。我用 matchQuery() 这里搜索“ 名称 ”字段并返回 User 信息。但是,班级有许多不同类型的可用 。例如,用于 搜索特定范围内的字段值,例如10到20年之间的年龄。有一种 方法可以使用通配符搜索字段:
@GetMapping(<font>"/view/name/{field}"</font><font>) <b>public</b> Map<String, Object> searchByName(@PathVariable <b>final</b> String field) { Map<String,Object> map = <b>null</b>; SearchResponse response = client.prepareSearch(</font><font>"users"</font><font>) .setTypes(</font><font>"employee"</font><font>) .setSearchType(SearchType.QUERY_AND_FETCH) .setQuery(QueryBuilders..matchQuery(</font><font>"name"</font><font>, field)) .get() ; List<SearchHit> searchHits = Arrays.asList(response.getHits().getHits()); map = searchHits.get(0).getSource(); <b>return</b> map; } </font>
4.通过使用Id搜索文档来更新文档并替换字段值。客户端有一个名为的方法 update()。它接受 UpdateRequest 更新查询的输入。
@GetMapping(<font>"/update/{id}"</font><font>) <b>public</b> String update(@PathVariable <b>final</b> String id) throws IOException { UpdateRequest updateRequest = <b>new</b> UpdateRequest(); updateRequest.index(</font><font>"users"</font><font>) .type(</font><font>"employee"</font><font>) .id(id) .doc(jsonBuilder() .startObject() .field(</font><font>"name"</font><font>, </font><font>"Rajesh"</font><font>) .endObject()); <b>try</b> { UpdateResponse updateResponse = client.update(updateRequest).get(); System.out.println(updateResponse.status()); <b>return</b> updateResponse.status().toString(); } <b>catch</b> (InterruptedException | ExecutionException e) { System.out.println(e); } <b>return</b> </font><font>"Exception"</font><font>; } </font>
5.最后一种方法是展示如何删除索引和类型的文档。客户端确实有一个 prepareDelete() 接受索引,类型和id的方法来删除文档。
@GetMapping(<font>"/delete/{id}"</font><font>) <b>public</b> String delete(@PathVariable <b>final</b> String id) { DeleteResponse deleteResponse = client.prepareDelete(</font><font>"users"</font><font>, </font><font>"employee"</font><font>, id).get(); <b>return</b> deleteResponse.getResult().toString(); } </font>
代码见: GitHub .
测试应用
该应用程序将在http://localhost:8102URL 上运行 。现在让我们测试一下我们上面讨论过的几个用例。
1.测试创建文档。
通过curl 或Postman 启动 。http://localhost:8102/rest/users/createPOST
输入:
{ <font>"userId"</font><font>:</font><font>"1"</font><font>, </font><font>"name"</font><font>: </font><font>"Sumit"</font><font>, </font><font>"userSettings"</font><font>: { </font><font>"gender"</font><font> : </font><font>"male"</font><font>, </font><font>"occupation"</font><font> : </font><font>"CA"</font><font>, </font><font>"hobby"</font><font> : </font><font>"chess"</font><font> } } </font>
您将看到显示“已创建”的响应。
2.要测试文档是否已创建,让我们测试视图功能。
启动。http://localhost:8102/rest/users/view/1GET
作为响应,您将看到id的用户信息,其值为“1”。
{ <font>"userSettings"</font><font>: { </font><font>"occupation"</font><font>: </font><font>"CA"</font><font>, </font><font>"gender"</font><font>: </font><font>"male"</font><font>, </font><font>"hobby"</font><font>: </font><font>"chess"</font><font> }, </font><font>"name"</font><font>: </font><font>"Rajesh"</font><font> } </font>
3.您可以通过名称字段查看用户信息以及启动 http://localhost:8102/rest/users/view/name/Rajesh。这是将“Rajesh”作为“名称”字段值传递。
同样,可以通过启动 和 来测试更新和删除功能 。http://localhost:8102/rest/users/update/1http://localhost:8102/rest/users/delete/1