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 public interface UserRepository extends 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=true 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 = "my_index", type = "user") public class User { @Id private String userId; private String name; private Date creationDate = new Date(); private Map<String, String> userSettings = new HashMap<>(); //getter and setters } |
控制器
第一个控制器是 UserController。它将使用 UserDAOImpl 让 ElasticserachTemplate 与Elasticsearch Engine 交互 。
@RestController public class UserController { @Autowired private UserDAO userDAO; @RequestMapping("/all") public List<User> getAllUsers() { return userDAO.getAllUsers(); } @RequestMapping(value = "/new", method = RequestMethod.POST) public User addUsers(@RequestBody User user) { userDAO.addNewUser(user); return user; } --- Other methods } |
UserDAOImpl - 此类初始化elasticsearchtemplate并使用queryForList方法检索数据。
@Repository public class UserDAOImpl implements UserDAO { private final Logger LOG = LoggerFactory.getLogger(getClass()); @Value("${elasticsearch.index.name}") private String indexName; @Value("${elasticsearch.user.type}") private String userTypeName; @Autowired private ElasticsearchTemplate esTemplate; @Override public List<User> getAllUsers() { SearchQuery getAllQuery = new NativeSearchQueryBuilder() .withQuery(matchAllQuery()).build(); return esTemplate.queryForList(getAllQuery, User.class); } // Other methods } |
另一个Controller是UserRepositoryConroller。这是使用UserRepository与elasticsearch引擎进行交互。
@RestController @RequestMapping("/repo") public class UserRepositoryController { @Autowired private UserRepository userRepository; @RequestMapping("/all") public List<User> getAllUsers() { List<User> users = new ArrayList<>(); userRepository.findAll().forEach(users::add); return users; } //Other methods } |
此Repository类扩展了ElasticsearchRepository类,该类在内部扩展了 ElasticsearchCrudRepository - > PagingAndSortingRepository
@Repository public interface UserRepository extends 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数据。
{ "name": "Sumit", "userSettings": { "gender" : "male", "occupation" : "CA", "hobby" : "chess" } } |
第2步 - 检查响应。您将看到使用userId生成的新用户,该文档是此文档的唯一ID。输出如下:
{ "userId": "AWdj-3KcTJbZRlQtLZfO", "name": "Sumit", "creationDate": 1543570682521, "userSettings": { "gender": "male", "occupation": "CA", "hobby": "chess" } } |
第3步 - 检索所有用户。使用 http://localhost:8102/all
{ "userId": "AWdj-3KcTJbZRlQtLZfO", "name": "Sumit", "creationDate": 1543570682521, "userSettings": { "gender": "male", "occupation": "CA", "hobby": "chess" } }, { "userId": "AWdZuKFRgzULDLBu_Y0c", "name": "Suresh", "creationDate": 1543398531296, "userSettings": {} } |
测试 使用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 对象。这将用于创建与索引和类型关联的用户文档。
public class User { private String userId; private String name; private Date creationDate = new Date(); private Map<String, String> userSettings = new HashMap<>(); -- getter/setter methods } |
创建Java配置文件以创建连接到Elasticsearch集群节点的传输客户端。它还从application.properties文件配置的环境加载主机和端口的值 。
@Configuration public class config{ @Value("${elasticsearch.host:localhost}") public String host; @Value("${elasticsearch.port:9300}") public int port; public String getHost() { return host; } public int getPort() { return port; } @Bean public Client client(){ TransportClient client = null; try{ System.out.println("host:"+ host+"port:"+port); client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port)); } catch (UnknownHostException e) { e.printStackTrace(); } return client; } } |
UserController 创建以展示以下功能:
- 创建一个名为“ users ” 的索引并键入“ employee ”。它将创建一个用于存储用户信息的文档。文档的id可以作为JSON输入传递,如果没有传递,Elasticsearch将生成自己的id。客户端有一个称为方法 prepareIndex() 构建文档对象和存储针对索引和类型。这方法是一种 POST 方法调用,其中 User 信息将作为JSON传递。
@Autowired Client client; @PostMapping("/create") public String create(@RequestBody User user) throws IOException { IndexResponse response = client.prepareIndex("users", "employee", user.getUserId()) .setSource(jsonBuilder() .startObject() .field("name", user.getName()) .field("userSettings", user.getUserSettings()) .endObject() ) .get(); System.out.println("response id:"+response.getId()); return response.getResult().toString(); } |
2.根据传递的“id”查看用户信息。客户端有一种 prepareGet() 方法可以根据索引,类型和id检索信息。它将以JSON格式返回用户信息。
@GetMapping("/view/{id}") public Map<String, Object> view(@PathVariable final String id) { GetResponse getResponse = client.prepareGet("users", "employee", id).get(); return getResponse.getSource(); } |
3.根据字段名称查看用户信息。我用 matchQuery() 这里搜索“ 名称 ”字段并返回 User 信息。但是,班级有许多不同类型的可用 。例如,用于 搜索特定范围内的字段值,例如10到20年之间的年龄。有一种 方法可以使用通配符搜索字段:
@GetMapping("/view/name/{field}") public Map<String, Object> searchByName(@PathVariable final String field) { Map<String,Object> map = null; SearchResponse response = client.prepareSearch("users") .setTypes("employee") .setSearchType(SearchType.QUERY_AND_FETCH) .setQuery(QueryBuilders..matchQuery("name", field)) .get() ; List<SearchHit> searchHits = Arrays.asList(response.getHits().getHits()); map = searchHits.get(0).getSource(); return map; } |
4.通过使用Id搜索文档来更新文档并替换字段值。客户端有一个名为的方法 update()。它接受 UpdateRequest 更新查询的输入。
@GetMapping("/update/{id}") public String update(@PathVariable final String id) throws IOException { UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index("users") .type("employee") .id(id) .doc(jsonBuilder() .startObject() .field("name", "Rajesh") .endObject()); try { UpdateResponse updateResponse = client.update(updateRequest).get(); System.out.println(updateResponse.status()); return updateResponse.status().toString(); } catch (InterruptedException | ExecutionException e) { System.out.println(e); } return "Exception"; } |
5.最后一种方法是展示如何删除索引和类型的文档。客户端确实有一个 prepareDelete() 接受索引,类型和id的方法来删除文档。
@GetMapping("/delete/{id}") public String delete(@PathVariable final String id) { DeleteResponse deleteResponse = client.prepareDelete("users", "employee", id).get(); return deleteResponse.getResult().toString(); } |
代码见:GitHub.
测试应用
该应用程序将在http://localhost:8102URL 上运行 。现在让我们测试一下我们上面讨论过的几个用例。
1.测试创建文档。
通过curl 或Postman 启动 。http://localhost:8102/rest/users/createPOST
输入:
{ "userId":"1", "name": "Sumit", "userSettings": { "gender" : "male", "occupation" : "CA", "hobby" : "chess" } } |
您将看到显示“已创建”的响应。
2.要测试文档是否已创建,让我们测试视图功能。
启动。http://localhost:8102/rest/users/view/1GET
作为响应,您将看到id的用户信息,其值为“1”。
{ "userSettings": { "occupation": "CA", "gender": "male", "hobby": "chess" }, "name": "Rajesh" } |
3.您可以通过名称字段查看用户信息以及启动 http://localhost:8102/rest/users/view/name/Rajesh。这是将“Rajesh”作为“名称”字段值传递。
同样,可以通过启动 和 来测试更新和删除功能 。http://localhost:8102/rest/users/update/1http://localhost:8102/rest/users/delete/1