1 环境准备
预备知识:
要将搜索的功能与前端对接,我们必须要使用Java代码来实现对Elasticsearch的操作。由于之前这些文章中的?JavaApi都是散装的所以用这一篇进行汇总.
官网API地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high.html
1.1 准备IDEA项目结构
- 创建elasticsearch_example项目
- 创建包结构如下所示
1.2 准备POM依赖
<repositories><!-- 代码库 --> <repository> <id>aliyun</id> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> <updatePolicy>never</updatePolicy> </snapshots> </repository> </repositories> <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.6.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <target>1.8</target> <source>1.8</source> </configuration> </plugin> </plugins> </build>
1.3 创建用于保存职位信息的实体类
注意:
在id字段上添加一个 @JSONField注解,并配置注解的serialize为false,表示该字段无需转换为JSON,因为它就是文档的唯一ID。
参考代码:
public class JobDetail { // 因为此处无需将id序列化为文档中 @JSONField(serialize = false) private long id; // 唯一标识 private String area; // 职位所在区域 private String exp; // 岗位要求的工作经验 private String edu; // 学历要求 private String salary; // 薪资范围 private String job_type; // 职位类型(全职/兼职) private String cmp; // 公司名 private String pv; // 浏览量 private String title; // 岗位名称 private String jd; // 职位描述 public long getId() { return id; } public void setId(long id) { this.id = id; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } public String getExp() { return exp; } public void setExp(String exp) { this.exp = exp; } public String getEdu() { return edu; } public void setEdu(String edu) { this.edu = edu; } public String getSalary() { return salary; } public void setSalary(String salary) { this.salary = salary; } public String getJob_type() { return job_type; } public void setJob_type(String job_type) { this.job_type = job_type; } public String getCmp() { return cmp; } public void setCmp(String cmp) { this.cmp = cmp; } public String getPv() { return pv; } public void setPv(String pv) { this.pv = pv; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getJd() { return jd; } public void setJd(String jd) { this.jd = jd; } @Override public String toString() { return "JobDetail{" + "id=" + id + ", area='" + area + '\'' + ", exp='" + exp + '\'' + ", edu='" + edu + '\'' + ", salary='" + salary + '\'' + ", job_type='" + job_type + '\'' + ", cmp='" + cmp + '\'' + ", pv='" + pv + '\'' + ", title='" + title + '\'' + ", jd='" + jd + '\'' + '}'; } }
1.4 编写接口和实现类
在cn.itcast.elasticsearch.service包中创建JobFullTextService接口,该接口中定义了职位全文检索相关的Java API接口。满足基本的增删改查
参考代码:
/** * 定义JobFullTextService */ public interface JobFullTextService { // 添加一个职位数据 void add(JobDetail jobDetail); // 根据ID检索指定职位数据 JobDetail findById(long id) throws IOException; // 修改职位薪资 void update(JobDetail jobDetail) throws IOException; // 根据ID删除指定位置数据 void deleteById(long id) throws IOException; // 根据关键字检索数据 List<JobDetail> searchByKeywords(String keywords) throws IOException; // 分页检索 Map<String, Object> searchByPage(String keywords, int pageNum, int pageSize) throws IOException; // scroll分页解决深分页问题 Map<String, Object> searchByScrollPage(String keywords, String scrollId, int pageSize) throws IOException; // 关闭ES连接 void close() throws IOException; ; }
1.5 创建实现类
在cn.itcast.elasticsearch.service.impl包下创建一个实现类:JobFullTextServiceImpl,并实现上面的接口。
参考代码:
public class JobFullTextServiceImpl implements JobFullTextService { @Override public void add(JobDetail jobDetail) { } @Override public void update(JobDetail jobDetail) { } @Override public JobDetail findById(long id) { return null; } @Override public boolean deleteById(long id) { return false; } @Override public List<JobDetail> searchByKeywords(String keywords) { return null; } @Override public Map<String, Object> searchByPage(String keywords, int pageNum, int pageSize) { return null; } @Override public Map<String, Object> searchByScrollPage(String keywords, String scrollId, int pageSize) { return null; } }
2 添加职位数据
2.1 初始化客户端连接
- 使用RestHighLevelClient构建客户端连接。
- 基于RestClient.builder方法来构建RestClientBuilder
- 用HttpHost来添加ES的节点
参考代码:
private RestHighLevelClient restHighLevelClient; private static final String JOB_IDX_NAME = "job_idx"; public JobFullTextServiceImpl() { restHighLevelClient = new RestHighLevelClient(RestClient.builder( new HttpHost("node1.cn", 9200, "http") , new HttpHost("node2.cn", 9200, "http") , new HttpHost("node3.cn", 9200, "http") )); }
2.2 实现关闭客户端连接
@Override public void close() { try { restHighLevelClient.close(); } catch (IOException e) { e.printStackTrace(); } }
2.3 编写代码实现新增职位数据
实现步骤:
- 构建IndexRequest对象,用来描述ES发起请求的数据。
- 设置文档ID。
- 使用FastJSON将实体类对象转换为JSON。
- 使用IndexRequest.source方法设置文档数据,并设置请求的数据为JSON格式。
- 使用ES High level client调用index方法发起请求,将一个文档添加到索引中。
参考代码:
@Override public void add(JobDetail jobDetail) { // 1. 构建IndexRequest对象,用来描述ES发起请求的数据。 IndexRequest indexRequest = new IndexRequest(JOB_IDX_NAME); // 2. 设置文档ID。 indexRequest.id(jobDetail.getId() + ""); // 3. 构建一个实体类对象,并使用FastJSON将实体类对象转换为JSON。 String json = JSON.toJSONString(jobDetail); // 4. 使用IndexRequest.source方法设置请求数据。 indexRequest.source(json); try { // 5. 使用ES High level client调用index方法发起请求 restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } System.out.println("索引创建成功!"); }
常见错误:
java.lang.IllegalArgumentException: The number of object passed must be even but was [1] at org.elasticsearch.action.index.IndexRequest.source(IndexRequest.java:474) at org.elasticsearch.action.index.IndexRequest.source(IndexRequest.java:461)
原因:IndexRequest.source要求传递偶数个的参数,但只传递了1个
2.4 编写测试用例测试添加方法
- 在 test/java 目录中创建一个 cn.itcast.elasticsearch.service 包。
- 在cn.itcast.elasticsearch.service 包下创建一个JobFullTextServiceTest类。
- 在@BeforeTest中构建JobFullTextService对象,@AfterTest中调用close方法关闭连接。
- 编写测试用例,构建一个测试用的实体类,测试add方法。
参考代码:
public class JobFullTextServiceTest { private JobFullTextService jobFullTextService; @BeforeTest public void beforeTest() { jobFullTextService = new JobFullTextServiceImpl(); } @Test public void addTest() { // 1. 测试新增索引文档 jobFullTextService = new JobFullTextServiceImpl(); JobDetail jobDetail = new JobDetail(); jobDetail.setId(1); jobDetail.setArea("山东省"); jobDetail.setCmp("山东大学"); jobDetail.setEdu("本科及以上"); jobDetail.setExp("五年工作经验"); jobDetail.setTitle("大数据工程师"); jobDetail.setJob_type("全职"); jobDetail.setPv("1700次浏览"); jobDetail.setJd("会Hadoop就行"); jobDetail.setSalary("15k-19k/月"); jobFullTextService.add(jobDetail); } @AfterTest public void afterTest() { jobFullTextService.close(); } }
3 根据ID检索指定职位数据
3.1 实现步骤
- 构建GetRequest请求。
- 使用RestHighLevelClient.get发送GetRequest请求,并获取到ES服务器的响应。
- 将ES响应的数据转换为JSON字符串
- 并使用FastJSON将JSON字符串转换为JobDetail类对象
- 记得:单独设置ID
参考代码:
@Override public JobDetail findById(long id) throws IOException { // 1. 构建GetRequest请求。 GetRequest getRequest = new GetRequest(JOB_IDX_NAME, id + ""); // 2. 使用RestHighLevelClient.get发送GetRequest请求,并获取到ES服务器的响应。 GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); // 3. 将ES响应的数据转换为JSON字符串 String json = response.getSourceAsString(); // 4. 并使用FastJSON将JSON字符串转换为JobDetail类对象 JobDetail jobDetail = JSONObject.parseObject(json, JobDetail.class); // 5. 设置ID字段 jobDetail.setId(id); return jobDetail; }
3.2 编写测试用例
参考代码:
@Test public void findByIdTest() throws IOException { JobDetail jobDetail = jobFullTextService.findById(1); System.out.println(jobDetail); }
4 修改职位
4.1 实现步骤
- 判断对应ID的文档是否存在
a) 构建GetRequest
b) 执行client的exists方法,发起请求,判断是否存在
- 构建UpdateRequest请求
- 设置UpdateRequest的文档,并配置为JSON格式
- 执行client发起update请求
参考代码:
@Override public void update(JobDetail jobDetail) throws IOException { // 1. 判断对应ID的文档是否存在 // a) 构建GetRequest GetRequest getRequest = new GetRequest(JOB_IDX_NAME, jobDetail.getId() + ""); // b) 执行client的exists方法,发起请求,判断是否存在 boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); if(!exists) return; // 2. 构建UpdateRequest请求 UpdateRequest updateRequest = new UpdateRequest(JOB_IDX_NAME, jobDetail.getId() + ""); // 3. 设置UpdateRequest的文档,并配置为JSON格式 updateRequest.doc(JSON.toJSONString(jobDetail), XContentType.JSON); // 4. 执行client发起update请求 restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); }
4.2 编写测试用例
- 将ID为1的职位信息查询出来
- 将职位的名称设置为:”大数据开发工程师”
- 执行更新操作
- 再打印查看职位的名称是否成功更新
参考代码:
@Test public void updateTest() throws IOException { JobDetail jobDetail = jobFullTextService.findById(1); jobDetail.setTitle("大数据开发工程师"); jobFullTextService.update(jobDetail); System.out.println(jobFullTextService.findById(1)); }