引入

目前,项目中使用常规的mysql语句实现了查询功能,比如对岗位的查询主要使用了下面的动态SQL语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<select id="getAllJobDynamically" resultType="com.qdu.entity.Job">
select * from Job
<where>
<if test="company!=null">
jId in(
select jId from company_job where cEmail=#{company.cEmail}
)
</if>
<if test="tag!=null">
and jId in(
select jId from job_tag where tId=#{tag.tId}
)
</if>
</where>
<if test="order==1">
order by jWage asc
</if>
<if test="order==2">
order by jWage desc
</if>
</select>

然而,实际上有一种更加专业的方式实现搜索,那就是Elasticsearch。

Elasticsearch简介

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式的全文搜索引擎,基于restful web接口。Elasticsearch是用Java语言开发的,基于Apache协议的开源项目,是目前最受欢迎的企业搜索引擎。Elasticsearch广泛运用于云计算中,能够达到实时搜索,具有稳定,可靠,快速的特点。

在安装并运行Es服务后,可以再安装Kibana作为Es的客户端,并使用默认的端口访问客户端:

http://localhost:5601

整合Elasticsearch实现搜索

1.在pom.xml中添加相关依赖;

1
2
3
4
5
<!--Elasticsearch相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2.修改application.yml配置文件,在spring节点下添加Elasticsearch相关配置;

1
2
3
4
5
6
7
spring:
data:
elasticsearch:
repositories:
enabled: true # 开启ES仓库配置,自动为仓库接口生成实现类
elasticsearch:
uris: http://localhost:9200 # ES的连接地址及端口号

3.实现岗位搜索功能

对实体类添加注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 岗位实体类,用于存储平台投放的岗位基本信息
*
* @author AaronWu
* jId 工作岗位id int类型,自增主键
* jName 工作名称
* jWage 工作薪水
* jInfo 工作信息
*/

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(indexName = "job_index", type = "job")
public class Job {
private int jId;
private String jName;
private int jWage;
private String jInfo;
private Tag tag;

public Job(String jName, int jWage, String jInfo) {
this.jName = jName;
this.jWage = jWage;
this.jInfo = jInfo;
}
}

创建Repository接口,继承ElasticsearchRepository,并添加自定义查询方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface JobRepository extends ElasticsearchRepository<Job, String> {

// 根据公司邮箱查询
List<Job> findByCEmail(String cEmail);

// 根据标签ID查询
List<Job> findByTagsContaining(String tagId);

// 按工资排序
Page<Job> findAll(Sort sort);

// 合成查询方法,根据条件筛选并排序
default List<Job> searchJobs(@Nullable String companyEmail, @Nullable String tagId, Integer order) {
List<Job> jobs = new ArrayList<>();

if (companyEmail != null) {
jobs.addAll(findByCEmail(companyEmail));
}

if (tagId != null) {
jobs.retainAll(findByTagsContaining(tagId)); // 保留同时满足公司和标签条件的职位
}

Sort.Order sortOrder;
if (order == 1) {
sortOrder = new Sort.Order(Sort.Direction.ASC, "jWage");
} else if (order == 2) {
sortOrder = new Sort.Order(Sort.Direction.DESC, "jWage");
} else {
sortOrder = new Sort.Order(Sort.DEFAULT_DIRECTION, "jWage"); // 默认排序
}

return findAll(new Sort(sortOrder)).getContent();
}
}

搜索功能异常问题

在实现简单的搜索后,测试功能发现问题。

例如,搜索名称为“后端”的岗位,并不能查询到名称为“Java后端开发”的岗位。而只能通过精准查询岗位名称实现。这种查询效果不太能让人满意。

查阅资料发现,对于汉字,在Elasticsearch中,如果未安装支持中文分词的插件(如ik分词器),或者虽然安装了但没有正确配置使用,当索引和搜索时就可能出现词汇粒度不一致的情况。

后续通过安装插件,解决了这个问题。