1、引入依赖
pom.xml 中引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
2、添加 ES 相关配置
application.yml 中配置
# spring 相关配置
spring:
# elasticsearch 配置
elasticsearch:
rest:
# ip是服务器ip地址
uris: http://8.xxx.xx.45:9200
# 我没有设置账号密码,所以下面可以不配置
#username:
#password:
3、相关注解介绍
ES 几个常用注解
@Document:声明索引库配置
-
- indexName:索引库名称
- type:映射类型。如果未设置,则使用小写的类的简单名称。(从版本4.0开始不推荐使用)
- shards:分片数量,默认 5
- replicas:副本数量,默认 1
- @Id:声明实体类的id
- @Field:声明字段属性
- type:字段的数据类型
- analyzer:指定在存储时候使用的分词器类型
- searchAnalyzer:指定在搜索时候使用的分词器类型
- index:是否创建索引
4、实体类
/**
* @Auther: csp1999
* @Date: 2020/11/24/8:55
* @Description: 帖子实体类
*/
// Lombok 相关注解
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@ToString
// ES 相关注解
@Document(indexName = "discusspost",shards = 5,replicas = 1)// discusspost 必须全小写
public class DiscussPost {
/**
* 主键id
*/
@Id
private int id;
/**
* 用户主键id
*/
@Field(type = FieldType.Long)
private int userId;
/**
* 帖子标题
*/
@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_smart")
private String title;
/**
* 帖子内容
*/
@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_smart")
private String content;
/**
* 帖子类型
* 0-普通; 1-置顶;
*/
@Field(type = FieldType.Integer)
private int type;
/**
* 帖子状态
* 0-正常; 1-精华; 2-拉黑;
*/
@Field(type = FieldType.Integer)
private int status;
/**
* 帖子创建日期
*/
@Field(type = FieldType.Date, format = DateFormat.custom,pattern = "yyyy-MM-dd")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd",timezone="GMT+8")
private Date createTime;
/**
* 帖子评论数量
*/
@Field(type = FieldType.Integer)
private int commentCount;
/**
* 帖子得分
*/
@Field(type = FieldType.Float)
private double score;
}
5、Repository 接口
/**
* @Auther: csp1999
* @Date: 2020/11/30/21:01
* @Description: 帖子相关的Repository
*/
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost,Integer> {
}
6、执行测试
/**
* @Auther: csp1999
* @Date: 2020/11/30/21:04
* @Description: ES 测试
*/
@SpringBootTest
public class ElasticSearchTest {
/**
* 从mysql数据中获取数据
*/
@Autowired
private DiscussPostMapper discussPostMapper;
/**
* 注入 DiscussPostRepository
*/
@Autowired
private DiscussPostRepository discussPostRepository;
/**
* 有些情况 DiscussPostRepository 处理不了
* 所以需要额外的 ElasticsearchRestTemplate
*/
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void testInsert(){
// 从数据库查询 id 为217 282 283 284 的帖子存入 ES 中
discussPostRepository.save(discussPostMapper.selectDiscussPostById(217));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(282));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(283));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(284));
}
}
运行测试代码,如果执行成功后,使用Postman 测试查看 ES 中的索引库内容:
可以看出,索引库已经创建好了!
我们来查一些数据内容:
结果为:
{
"took": 249,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "discusspost",
"_type": "_doc",
"_id": "282",
"_score": 1.0,
"_source": {
"_class": "com.haust.community.pojo.DiscussPost",
"id": 282,
"userId": 152,
"title": "哈哈***哈哈",
"content": "***哈哈",
"type": 0,
"status": 0,
"createTime": "2020-11-25",
"commentCount": 1,
"score": 0.0
}
},
{
"_index": "discusspost",
"_type": "_doc",
"_id": "284",
"_score": 1.0,
"_source": {
"_class": "com.haust.community.pojo.DiscussPost",
"id": 284,
"userId": 153,
"title": "海贼王我当定了!",
"content": "海贼王我当定了!",
"type": 0,
"status": 0,
"createTime": "2020-11-29",
"commentCount": 2,
"score": 0.0
}
},
{
"_index": "discusspost",
"_type": "_doc",
"_id": "217",
"_score": 1.0,
"_source": {
"_class": "com.haust.community.pojo.DiscussPost",
"id": 217,
"userId": 103,
"title": "互联网求职暖春计划",
"content": "今年的就业形势,确实不容乐观。过了个年,仿佛跳水一般,整个讨论区哀鸿遍野!19届真的没人要了吗?!18届被优化真的没有出路了吗?!大家的“哀嚎”与“悲惨遭遇”牵动了每日潜伏于讨论区的牛客小哥哥小姐姐们的心,于是牛客决定:是时候为大家做点什么了!为了帮助大家度过“艰难”,牛客网特别联合60+家企业,开启互联网求职暖春计划,面向18届&19届,拯救0 offer!",
"type": 0,
"status": 0,
"createTime": "2019-04-04",
"commentCount": 0,
"score": 0.0
}
},
{
"_index": "discusspost",
"_type": "_doc",
"_id": "283",
"_score": 1.0,
"_source": {
"_class": "com.haust.community.pojo.DiscussPost",
"id": 283,
"userId": 152,
"title": "海贼王我当定了!",
"content": "Hello World!",
"type": 0,
"status": 0,
"createTime": "2020-11-25",
"commentCount": 3,
"score": 0.0
}
}
]
}
}
7、SpringBoot 操作ES增删改
/**
* @Auther: csp1999
* @Date: 2020/11/30/21:04
* @Description: ES 测试
*/
@SpringBootTest
public class ElasticSearchTest {
/**
* 从mysql数据中获取数据
*/
@Autowired
private DiscussPostMapper discussPostMapper;
/**
* 注入 DiscussPostRepository
*/
@Autowired
private DiscussPostRepository discussPostRepository;
/**
* 有些情况 DiscussPostRepository 处理不了
* 所以需要额外的 ElasticsearchRestTemplate
*/
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* 创建/更新索引
*/
@Test
public void testCreateIndex() {
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(DiscussPost.class);
Document document = indexOperations.createMapping(DiscussPost.class);
//boolean bool = indexOperations.create(document);
boolean bool = indexOperations.putMapping(document);
System.out.println(bool?"成功":"失败");
}
/**
* 每次只插入一条
*/
@Test
public void testInsert() {
// 从数据库查询 id 为217 282 283 284 的帖子存入 ES 中
discussPostRepository.save(discussPostMapper.selectDiscussPostById(217));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(282));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(283));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(284));
}
/**
* 批量插入
*/
@Test
public void testInsertAll() {
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(101,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(102,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(103,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(152,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(153,0,100));
}
/**
* 测试修改
*/
@Test
public void testUpdate() {
DiscussPost discussPost = discussPostMapper.selectDiscussPostById(203);
discussPost.setContent("海贼王,路飞当定了~");
discussPostRepository.save(discussPost);
}
/**
* 测试删除
*/
@Test
public void testDelete() {
// discussRepository.deleteById(203);
discussPostRepository.deleteAll();//全部删除
}
}
8、SpringBoot 操作ES 高亮搜索(核心)
效果如图:
将从ES 中查询的内容,把搜索的关键字高亮显示借助<em> 标签:
参考代码:
@Test
public void testSearchByTemplate() {
// 构建查询条件
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))// 按照帖子分类排序
.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))// 按照帖子分数排序
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))// 按照帖子发布日期排序
.withPageable(PageRequest.of(0, 10))// 每页十条数据
.withHighlightFields(
// 标题和内容中的匹配字段高亮展示
new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
).build();
// 得到查询结果返回容纳指定内容对象的集合SearchHits
SearchHits<DiscussPost> searchHits = elasticsearchRestTemplate.search(searchQuery, DiscussPost.class);
// 设置一个需要返回的实体类集合
List<DiscussPost> discussPosts = new ArrayList<>();
// 遍历返回的内容进行处理
for (SearchHit<DiscussPost> searchHit : searchHits) {
// 高亮的内容
Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
// 将高亮的内容填充到content中
searchHit.getContent().setTitle(highlightFields.get("title") == null ?
searchHit.getContent().getTitle() : highlightFields.get("title").get(0));
searchHit.getContent().setTitle(highlightFields.get("content") == null ?
searchHit.getContent().getContent() : highlightFields.get("content").get(0));
// 放到实体类中
discussPosts.add(searchHit.getContent());
}
// 输出结果
System.out.println(discussPosts.size());
for (DiscussPost discussPost : discussPosts) {
System.out.println(discussPost);
}
}
总结
(1)Elasticsearch可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据,服务大公司;也可以运行在单机上,服务小公司。
(2)Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES;lucene(全文检索),商用的数据分析软件(也是有的),分布式数据库(mycat)。
(3)对用户而言,是开箱即用的,非常简单,作为中小型的应用,直接3分钟部署一下ES,就可以作为生产环境的系统来使用了,数据量不大,操作不是太复杂。