ElasticSearch的介绍与安装
对ElasticSearch进行原生的CRUD以及分页操作
什么是Spring Data ElasticSearch
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快 捷,并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法,可以在几乎不用写实现 的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。
Spring Data的官网:http://projects.spring.io/spring-data/
使用Spring Data ElasticSearch对ElasticSearch进行CRUD以及分页操作
- pom文件
<!--添加elasticsearch坐标-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.8</version>
</dependency>
<!--添加elasticsearch客户端坐标-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.8</version>
</dependency>
<!--Spring Data ElasticSearch坐标-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.0.5.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
<!--测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
- 配置文件【applicationContext.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
">
<!-- 配置server包扫描 -->
<context:component-scan base-package="com.test.server"/>
<!--
配置elasticSearch的连接
cluster-nodes:配置节点信息 配置节点信息 多个节点之间用逗号隔开 例:cluster-nodes="localhost:9300,localhost:9400"
cluster-name:配置集群名 默认为elasticsearch
-->
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" cluster-name="elasticsearch"/>
<!-- ElasticSearch模版对象 -->
<bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"></constructor-arg>
</bean>
<!-- 配置Dao包扫描 -->
<elasticsearch:repositories base-package="com.test.dao"/>
</beans>
- entity实体类
package com.test.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* 创建一个Elasticsearch文档的实体类对象
*/
//文档对象 indexName: 索引名 type: 类型名
@Document(indexName = "data_es_blog", type = "data_es_article")
public class EsDocument {
@Id //文档主键 唯一的标识
//字段配置 store: 是否存储 index: 是否索引 type: 字段类型
@Field(store = true, index = false, type = FieldType.Long)
private Long id; //id
//字段配置 analyzer: 插入文档时是否分词,并指定分词器 searchAnalyzer: 查询时是否分词,并指定分词器 注意:不指定使用默认标准分词器
@Field(store = true, index = true, analyzer = "ik_smart", searchAnalyzer = "ik_smart", type = FieldType.text)
private String title; //标题
@Field(store = true, index = true, analyzer = "ik_smart", searchAnalyzer = "ik_smart", type = FieldType.text)
private String content; //内容
public EsDocument() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "EsDocument{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
- dao层
如果自定义方法,满足Spring Data ElasticSearch的命名规则,所以只需要定义接口,不需要实现,命名规则图会放在最后
注意:
1. Spring Data ElasticSearch的查询会先分词在查询 但是分词之后的多个关键词之间的使用and连接, 也就是说需要满足所有的关键词才会查询出。
2. 使用ElasticSearch原生查询在查询时也是先分词在查询 但是分词之后的多个关键字为or或者的关系,也就是说只要满足其中一个关键字即可查询到
package com.test.dao;
import com.test.entity.EsDocument;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface EsDao extends ElasticsearchRepository<EsDocument, Long> {//指定实体类和id类型
/**
* 根据title作用域来查询 参数title:在title域进行检索的关键字
*
* 此方法是按照Spring Data ElasticSearch的命名规则来写的,所以只需要定义接口,不需要实现
* 此查询会先分词在查询 但是分词之后的多个关键词之间的使用and连接
* 也就是说需要满足所有的关键词才会查询出
* @param title
* @return
*/
List<EsDocument> findEsDocumentByTitle(String title);
/**
* 根据title和content作用域来查询 需同时满足
* 参数title:在title域进行检索的关键字
* 参数content:在content域进行检索的关键字
* 此方法是按照Spring Data ElasticSearch的命名规则来写的,所以只需要定义接口,不需要实现
* 此查询会先分词在查询 但是分词之后的多个关键词之间的使用and连接
* 也就是说需要满足所有的关键词才会查询出
* @param title
* @param content
* @return
*/
List<EsDocument> findEsDocumentByTitleAndContent(String title,String content);
}
- server层
package com.test.server;
import com.test.entity.EsDocument;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface EsServer {
//保存文档
EsDocument save(EsDocument esDocument);
//更新文档
void update(EsDocument esDocument);
//根据ID删除
void deleteById(Long id);
//根据对象删除文档
void delete(EsDocument esDocument);
//删除全部
void deleteAll();
//根据id查询
EsDocument findById(Long id);
//根据id组查询
List<EsDocument> findAllById(List<Long> ids);
//查询所有
List<EsDocument> findAll();
//自定义查询 根据title作用域来查询
List<EsDocument> findEsDocumentByTitle(String title);
//自定义查询 根据title和content作用域来查询
List<EsDocument> findEsDocumentByTitleAndContent(String title,String content);
//分页查询
List<EsDocument> findAllByPage1(Pageable pageable);
//分页查询
Page<EsDocument> findAllByPage2(Pageable pageable);
}
- 实现类 impl
package com.test.server.impl;
import com.test.dao.EsDao;
import com.test.entity.EsDocument;
import com.test.server.EsServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
@Service
public class EsServerImpl implements EsServer {
@Autowired
private EsDao esDao;
/**
* 保存文档
*
* @param esDocument
*/
public EsDocument save(EsDocument esDocument) {
EsDocument save = esDao.save(esDocument);
return save;
}
/**
* 更新文档
*
* @param esDocument
*/
public void update(EsDocument esDocument) {
esDao.save(esDocument);
}
/**
* 根据ID删除
*
* @param id
*/
public void deleteById(Long id) {
esDao.deleteById(id);
}
/**
* 删除文档
*
* @param esDocument
* @return
*/
public void delete(EsDocument esDocument) {
esDao.delete(esDocument);
}
/**
* 删除全部
*/
public void deleteAll() {
esDao.deleteAll();
}
/**
* 根据id查询
*
* @param id
* @return
*/
public EsDocument findById(Long id) {
Optional<EsDocument> result = esDao.findById(id);
return result.get();
}
/**
* 根据id组 查询数据
*
* @param ids
* @return
*/
@Override
public List<EsDocument> findAllById(List<Long> ids) {
Iterable<EsDocument> results = esDao.findAllById(ids);
//遍历结果集
return traverseResult(results);
}
/**
* 查询所有
*
* @return
*/
@Override
public List<EsDocument> findAll() {
Iterable<EsDocument> results = esDao.findAll();
//遍历结果集
return traverseResult(results);
}
/**
* 自定义查询 根据title作用域来查询
*
* @param title
* @return
*/
@Override
public List<EsDocument> findEsDocumentByTitle(String title) {
return esDao.findEsDocumentByTitle(title);
}
/**
* 自定义查询 根据title和content作用域来查询
*
* @param title
* @param content
* @return
*/
@Override
public List<EsDocument> findEsDocumentByTitleAndContent(String title, String content) {
return esDao.findEsDocumentByTitleAndContent(title, content);
}
/**
* 分页查询
*
* @return
*/
public List<EsDocument> findAllByPage1(Pageable pageable) {
Iterable<EsDocument> results = esDao.findAll(pageable);
//遍历结果集
return traverseResult(results);
}
/**
* 分页查询
*
* @param pageable
* @return
*/
@Override
public Page<EsDocument> findAllByPage2(Pageable pageable) {
return esDao.findAll(pageable);
}
/**
* 遍历结果集
*
* @return
*/
public List<EsDocument> traverseResult(Iterable<EsDocument> results) {
List<EsDocument> list = new ArrayList<>();
Iterator<EsDocument> iterator = results.iterator();
//遍历结果
while (iterator.hasNext()) {
//获取到对象
EsDocument esDocument = iterator.next();
list.add(esDocument);
}
return list;
}
}
- 测试
import com.test.entity.EsDocument;
import com.test.server.EsServer;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.List;
/**
* 使用Spring Data ElasticSearch对ElasticSearch进行CRUD以及分页
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class DataElasticSearchTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private EsServer esServer;
/**
* 使用ElasticsearchTemplate模板创建索引和映射
*/
@Test
public void createIndex() {
//创建索引 注意:顺序不要搞反了
elasticsearchTemplate.createIndex(EsDocument.class);
//设置映射 注意:顺序不要搞反了
elasticsearchTemplate.putMapping(EsDocument.class);
}
/**
* 创建文档
*/
@Test
public void save() {
EsDocument esDocument = new EsDocument();
//设置文档id
esDocument.setId(1L);
//设置文档标题
esDocument.setTitle("易卜生");
//设置文档内容
esDocument.setContent("不因幸运而固步自封,不因厄运而一蹶不振。真正的强者,善于从顺境中找到阴影,从逆境中找到光亮,时时校准自己前进的目标。");
//保存文档
EsDocument save = esServer.save(esDocument);
System.out.println(save.toString());
}
/**
* 更新文档 就是根据id会把原来的删掉在重新添加一遍
*/
@Test
public void update() {
EsDocument esDocument = new EsDocument();
//设置文档id
esDocument.setId(1L);
//设置文档标题
esDocument.setTitle("王勃");
//设置文档内容
esDocument.setContent("穷且益坚,不坠青云之志。");
//保存文档
esServer.update(esDocument);
}
/**
* 根据ID删除
*/
@Test
public void deleteById() {
esServer.deleteById(2L);
}
/**
* 根据对象删除文档
*/
@Test
public void delete() {
EsDocument esDocument = new EsDocument();
esDocument.setId(3l);
esServer.delete(esDocument);
}
/**
* 删除全部
*/
@Test
public void deleteAll() {
esServer.deleteAll();
}
/**
* 根据id查询
*/
@Test
public void findById() {
EsDocument esDocument = esServer.findById(1L);
System.out.println(esDocument);
}
/**
* 根据id组查询
*/
@Test
public void findAllById() {
//Long[] idArray = {1L, 2L, 4L};
Long[] idArray = {9L, 10L, 11L};
List<EsDocument> list = esServer.findAllById(Arrays.asList(idArray));
System.out.println(list.toString());
}
/**
* 查询所有
*/
@Test
public void findAll() {
List<EsDocument> list = esServer.findAll();
System.out.println(list.toString());
}
/**
* 自定义查询 根据title作用域来查询
* <p>
* 自定义查询
* 1. 需要按照Spring Data ElasticSearch的命名规则来写
* 2. 只需要定义方法无需实现
* 3. 自定义查询会先分词在查询 但是分词之后的多个关键词之间的使用and连接
* 也就是说需要满足所有的关键词才会查询出
*
* 注意:此查询和ElasticSearch的原生查询 一定要区分开
*/
@Test
public void findEsDocumentByTitle() {
List<EsDocument> list = esServer.findEsDocumentByTitle("王勃");
System.out.println(list.toString());
}
/**
* 自定义查询 根据title和content作用域来查询
* <p>
* 自定义查询
* 1. 需要按照Spring Data ElasticSearch的命名规则来写
* 2. 只需要定义方法无需实现
* 3. 自定义查询会先分词在查询 但是分词之后的多个关键词之间的使用and连接
* 也就是说需要满足所有的关键词才会查询出
*
* 注意:此查询和ElasticSearch的原生查询 一定要区分开
*/
@Test
public void findEsDocumentByTitleAndContent() {
List<EsDocument> list = esServer.findEsDocumentByTitleAndContent("易卜生", "不因幸运而固步自封,不因厄运而一蹶不振");
System.out.println(list.toString());
}
/**
* 自定义查询
* 使用ElasticSearch原生查询
* 1. 可以自定义查询条件
* 2. 在查询时也是先分词在查询 但是分词之后的多个关键字为or或者的关系
* 也就是说只要满足其中一个关键字即可查询到
*
* 注意:此查询和Spring Data ElasticSearch的自定义查询 一定要区分开
*/
@Test
public void nativeSearchQuery() {
//创建SearchQuery对象
SearchQuery query = new NativeSearchQueryBuilder()
//设置查询条件 以及查询的默认作用域
.withQuery(QueryBuilders.queryStringQuery("真正的强者,善于从顺境中找到阴影,从逆境中找到光亮").defaultField("content"))
//设置分页
.withPageable(PageRequest.of(0, 3))
.build();
//使用模板对象执行查询
List<EsDocument> list = elasticsearchTemplate.queryForList(query, EsDocument.class);
System.out.println(list.toString());
}
/**
* 分页查询
*/
@Test
public void findAllByPage1() {
//设置分页 从第几页开始,每页显示多少条
Pageable pageable = PageRequest.of(0, 3);
List<EsDocument> list = esServer.findAllByPage1(pageable);
// System.out.println(list.toString());
}
/**
* 分页查询
*/
@Test
public void findAllByPage2() {
//设置分页 从第几页开始,每页显示多少条
Pageable pageable = PageRequest.of(0, 3);
Page<EsDocument> esDocuments = esServer.findAllByPage2(pageable);
for (EsDocument esDocument : esDocuments.getContent()) {
System.out.println(esDocument);
}
}
@After
public void methodEnd() {
System.out.println("执行成功.....");
}
}
这是ElasticsearchRepository 继承CrudRepository类帮我们实现的CRUD方法
这是Spring Data ElasticSearch 自定义方法的命名规则
如有错误欢迎大家批评指正,谢谢