Elastic Search 6.5.1 集成Java客户端
前面了解了使用 HTTP 请求操作 ES,但是实际项目中操作,我们主要还是使用Java代码操作,所以尝试一下Java客户端连接ES基础已安装ES,且自己能够正常操作API,了解ES基本语法本地已安装IDE新建springboot工程pom.xml,主要是加入ES的依赖就好,版本号与ES服务器版本号一致,我的都是6.5.1<?xml version="1.0" en
·
前面了解了使用 HTTP 请求操作 ES,但是实际项目中操作,我们主要还是使用Java代码操作,所以尝试一下Java客户端连接ES
基础
- 已安装ES,且自己能够正常操作API,了解ES基本语法
- 本地已安装IDE
新建springboot工程
- pom.xml,主要是加入ES的依赖就好,版本号与ES服务器版本号一致,我的都是6.5.1
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.elastic</groupId> <artifactId>es-1</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>es-1</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/transport --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>6.5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- 客户端连接服务器,通过TransportClient,这里直接获取连接然后注入容器
package com.elastic.es1; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import java.net.InetAddress; import java.net.UnknownHostException; @Configuration @SpringBootApplication @ComponentScan("com.elastic.es1") public class Es1Application { public static void main(String[] args) { SpringApplication.run(Es1Application.class, args); } @Bean public TransportClient client() throws UnknownHostException { String hostName = "47.105.159.23"; TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(hostName), 9300); String clusterName = "cluster.name"; String nodeName = "gaojie"; Settings settings = Settings.builder().put(clusterName, nodeName).build(); TransportClient client = new PreBuiltTransportClient(settings); client.addTransportAddress(transportAddress); return client; } }
- 编写实体类,此处操作的是一个 employee 对象
public class EmployeeVo { private String id; // ID private String name; // 姓名 private String phone; // 电话 private Integer sex; // 性别 private Integer salary; // 工资 private String post; // 岗位 private String desc; // 描述 private Date joinTime; // 入职时间 private String keyword; // 关键字 private Integer minSalary; // 最小工资 private Integer maxSalary; // 最大工资 private Date startTime; // 开始时间 private Date endTime; // 结束时间 private Set<String> ids; // ID集合 private Object data; // 查询结果 private Long total; // 查询记录总数 private Integer from; // 起始位置 private Integer size; // 查询条数 public EmployeeVo(Object data, Long total) { this.data = data; this.total = total; } }
- 编写接口类,定义方法以及常量,避免便于维护和可读
package com.elastic.es1.service.interfaces; import com.elastic.es1.entity.vo.EmployeeVo; import java.io.IOException; public interface EmployeeService { void save(EmployeeVo vo) throws IOException; void delete(EmployeeVo vo); EmployeeVo search(EmployeeVo vo); String INDEX = "manage"; String TYPE = "employee"; String NAME = "name"; String PHONE = "phone"; String SEX = "sex"; String SALARY = "salary"; String POST = "post"; String DESC = "desc"; String JOIN_TIME = "joinTime"; }
- 方法实现(save方法,当传入ID时为修改,不传ID时为新增)
package com.elastic.es1.service.impl; import com.elastic.es1.entity.vo.EmployeeVo; import com.elastic.es1.service.interfaces.EmployeeService; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; @Service public class EmployeeServiceImpl implements EmployeeService { @Resource private TransportClient client; @Override public void save(EmployeeVo vo) throws IOException { XContentBuilder builder = this.getBuilder(vo); if (vo.getId() == null) { // 若不传入 ID 则表示新增 client.prepareIndex(INDEX, TYPE).setSource(builder).get(); } else { // 若传入 ID 则表示修改 client.prepareUpdate(INDEX, TYPE, vo.getId()).setDoc(builder).get(); } } /** * 将请求对象 EmployeeVo 转换成 builder 对象 */ private XContentBuilder getBuilder(EmployeeVo vo) throws IOException { XContentBuilder builder = jsonBuilder().startObject(); if (vo.getName() != null) { builder.field(NAME, vo.getName()); } if (vo.getPhone() != null) { builder.field(PHONE, vo.getPhone()); } if (vo.getPost() != null) { builder.field(POST, vo.getPost()); } if (vo.getDesc() != null) { builder.field(DESC, vo.getDesc()); } if (vo.getSex() != null) { builder.field(SEX, vo.getSex()); } if (vo.getSalary() != null) { builder.field(SALARY, vo.getSalary()); } return builder.endObject(); } @Override public void delete(EmployeeVo vo) { if (vo.getIds() != null) { vo.getIds().forEach(id -> client.prepareDelete(INDEX, TYPE, id).get()); } } @Override public EmployeeVo search(EmployeeVo vo) { // boolQuery :可以叠加多个查询条件,相当于SQL的 AND BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // multiMatchQuery :多字段搜索,输入关键字,可以从多个字段匹配 if (vo.getKeyword() != null) { boolQueryBuilder.must(QueryBuilders.multiMatchQuery(vo.getKeyword(), NAME, PHONE, POST, DESC)); } // matchQuery :单字段搜索 if (vo.getName() != null) { boolQueryBuilder.must(QueryBuilders.matchQuery(NAME, vo.getName())); } // wildcardQuery :通配符匹配:类似于SQL里面的 LIKE if (vo.getPhone() != null) { boolQueryBuilder.must(QueryBuilders.wildcardQuery(PHONE, "*" + vo.getPhone() + "*")); } if (vo.getPost() != null) { boolQueryBuilder.must(QueryBuilders.matchQuery(POST, vo.getPost())); } if (vo.getDesc() != null) { boolQueryBuilder.must(QueryBuilders.matchQuery(DESC, vo.getDesc())); } // termQuery : 通常用于非字符串类型的比较,比如性别为男的或者女的,状态为1或者2什么的。。总之比较固定值 if (vo.getSex() != null) { boolQueryBuilder.must(QueryBuilders.termQuery(SEX, vo.getSex())); } if (vo.getSalary() != null) { boolQueryBuilder.must(QueryBuilders.termQuery(SALARY, vo.getSalary())); } // rangeQuery :范围查询,判断一个值是否在范围内,比如工资大于多少,年龄多少之间,是否在有效期内。。。 if (vo.getMinSalary() != null || vo.getMaxSalary() != null) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(SALARY); if (vo.getMinSalary() != null) { // from :范围查询里面的下限值,包含该值 rangeQueryBuilder.from(vo.getMinSalary()); } if (vo.getMaxSalary() != null) { // to :范围查询里面的上限值,包含该值 rangeQueryBuilder.to(vo.getMaxSalary()); } boolQueryBuilder.filter(rangeQueryBuilder); } if (vo.getStartTime() != null || vo.getEndTime() != null) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(JOIN_TIME); if (vo.getStartTime() != null) { rangeQueryBuilder.from(vo.getStartTime()); } if (vo.getEndTime() != null) { rangeQueryBuilder.to(vo.getEndTime()); } boolQueryBuilder.filter(rangeQueryBuilder); } SearchRequestBuilder searchRequestBuilder = client.prepareSearch(INDEX).setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setQuery(boolQueryBuilder); // from :翻页参数,从第几条记录开始 if (vo.getFrom() != null) { searchRequestBuilder.setFrom(vo.getFrom()); } // size :翻页参数,查询的记录数 if (vo.getSize() != null) { searchRequestBuilder.setSize(vo.getSize()); } // sort : 排序规则,默认规则为ASC升序,可以修改排序规则也可以用多个字段 searchRequestBuilder.addSort(SortBuilders.fieldSort(SEX)) .addSort(SortBuilders.fieldSort(SALARY).order(SortOrder.DESC)); System.out.println("查询条件为|" + searchRequestBuilder); // 查询结果,由于数据都在 sourceAsMap 参数下,所以下面会再获取 sourceAsMap 的值 SearchHits hits = searchRequestBuilder.get().getHits(); List<Map<String, Object>> data = new ArrayList<>(); hits.forEach(hit -> { Map<String, Object> sourceAsMap = hit.getSourceAsMap(); sourceAsMap.put("_id", hit.getId()); data.add(sourceAsMap); }); return new EmployeeVo(data, hits.totalHits); } }
- 编写 Controller
package com.elastic.es1.controller; import com.elastic.es1.entity.vo.EmployeeVo; import com.elastic.es1.service.interfaces.EmployeeService; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.io.IOException; @RestController @RequestMapping("employee") public class EmployeeController { @Resource private EmployeeService employeeService; @PostMapping("save") public Object save(@RequestBody EmployeeVo vo) throws IOException { employeeService.save(vo); return "保存成功"; } @DeleteMapping("delete") public Object delete(@RequestBody EmployeeVo vo) { employeeService.delete(vo); return "删除成功"; } @GetMapping("search") public Object search(EmployeeVo vo) { return employeeService.search(vo); } }
- 修改 application.properties 端口号,因为默认端口为8080,防止冲突
server.port=9090
项目启动成功后,去Postman测试,都能够正常使用,这里只记录一个 search 请求
GET http://localhost:9090/employee/search?from=0&size=10
================================================
{
"id": null,
"name": null,
"phone": null,
"sex": null,
"salary": null,
"post": null,
"desc": null,
"joinTime": null,
"keyword": null,
"minSalary": null,
"maxSalary": null,
"startTime": null,
"endTime": null,
"ids": null,
"data": [
{
"post": "设计前端",
"phone": "18874797777",
"sex": 1,
"name": "桂禄",
"dept": {
"name": "设计中心",
"id": "1003"
},
"_id": "o1ZWmGcBof4Qu3GrG81P",
"salary": 50000,
"join_time": "2018-05-03",
"desc": "a front boy"
},
{
"post": "架构师",
"phone": "18874792222",
"sex": 1,
"name": "春哥",
"dept": {
"name": "技术中心",
"id": "1001"
},
"_id": "nlb-l2cBof4Qu3Gr8M1Y",
"salary": 35000,
"join_time": "2018-03-03",
"desc": "a framework boy"
},
{
"post": "设计UI",
"phone": "18874796666",
"sex": 1,
"name": "铜川",
"dept": {
"name": "设计中心",
"id": "1003"
},
"_id": "olYDmGcBof4Qu3Grw837",
"salary": 16000,
"join_time": "2018-04-03",
"desc": "a sunny boy"
},
{
"post": "Java工程师",
"phone": "18874796310",
"sex": 1,
"name": "高节",
"dept": {
"name": "技术中心",
"id": "1001"
},
"_id": "nFZul2cBof4Qu3GrDc0v",
"salary": 10000,
"join_time": "2018-12-03",
"desc": "a love of work boy"
},
{
"post": "IOS工程师",
"phone": "18874791111",
"sex": 2,
"name": "周益",
"dept": {
"name": "技术中心",
"id": "1001"
},
"_id": "nVZ-l2cBof4Qu3GrFc1L",
"salary": 15000,
"join_time": "2018-10-03",
"desc": "a IOS boy"
},
{
"post": "测试工程师",
"phone": "18874793333",
"sex": 2,
"name": "丽燕",
"dept": {
"name": "技术中心",
"id": "1001"
},
"_id": "n1YAmGcBof4Qu3GrB83o",
"salary": 12000,
"join_time": "2018-05-03",
"desc": "a beautiful girl"
},
{
"post": "Android工程师",
"phone": "18874794444",
"sex": 2,
"name": "李岳",
"dept": {
"name": "技术中心",
"id": "1001"
},
"_id": "oFYAmGcBof4Qu3Gr880L",
"salary": 12000,
"join_time": "2018-04-03",
"desc": "a rude man"
},
{
"post": "会计",
"phone": "18874795555",
"sex": 2,
"name": "青萍",
"dept": {
"name": "财务部门",
"id": "1002"
},
"_id": "oVYCmGcBof4Qu3Gr8c33",
"salary": 6000,
"join_time": "2018-08-03",
"desc": "a sunny girl"
}
],
"total": 8,
"from": null,
"size": null
}
更多推荐
已为社区贡献1条内容
所有评论(0)