搜索引擎ElasticSearch18_Spring Data ElasticSearch 使用6
一、Spring Data ElasticSearch简介
1、什么是Spring Data
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。
Spring Data的官网:http://projects.spring.io/spring-data/
Spring Data常用的功能模块如下:
2、什么是Spring Data ElasticSearch
Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 。Spring Data为Elasticsearch项目提供集成搜索引擎。Spring Data Elasticsearch POJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储库数据访问层。
官方网站:http://projects.spring.io/spring-data-elasticsearch/
二、Spring Data ElasticSearch入门
步骤:
1、工程搭建
1)创建一个Java工程
2)把相关jar包添加到工程中,如果maven工程就添加坐标
3)创建一个spring的配置文件
1. 配置TransportClient对象 elasticsearch:transport-client
2. 配置包扫描器 elasticsearch:repositories
3. 配置elasticsearchTemplate对象,就是一个bean
2、管理索引库
1)创建一个Entity对象,其实就是一个JavaBean(pojo)映射到一个文档上,需要添加一些注解进行标注。
2)创建一个Dao,是一个接口,需要继承ElasticSearchRepository接口。
3)编写测试代码
3、创建索引
直接使用ElasticSearchTemplate对象的createIndex方法创建索引,并配置映射关系。
4、添加、更新文档
1)创建一个Article对象
2)使用ArticleRepository对象向索引库中添加文档
5、删除文档
直接使用ArticleRepository对象的deleteById方法直接删除。
6、查询索引库
直接使用ArticleRepository对象的查询方法。
7、自定义查询方法
需要根据SpringDataES的命名规则来命名。
如果不设置分页信息,默认带分页,每页显示10条数据。
如果设置分页信息,应该在方法中添加一个参数Pageable,默认是从0页开始。
可以对搜索的内容先分词然后再进行查询。每个词之间都是and的关系
8、使用原生的查询条件查询
NativeSearchQuery对象。
使用方法:
1)创建一个NativeSearchQuery对象,设置查询条件,QueryBuilder对象
2)使用ElasticSearchTemplate对象执行查询
3)取查询结果
实现:
0)新建一个maven项目:springdata-elasticsearch
1)导入Spring Data ElasticSearch坐标
<?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.itheima</groupId> <artifactId>itheima_elasticsearch_demo3</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>5.6.8</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>5.6.8</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.24</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.8.1</version> </dependency> <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> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.4.RELEASE</version> </dependency> </dependencies> </project>
2)创建applicationContext.xml配置文件,引入elasticsearch命名空间
<?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 "> </beans>
3)编写实体Article
package com.itheima.domain; public class Article { private Integer id; private String title; private String content; public Integer getId() { return id; } public void setId(Integer 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 "Article [id=" + id + ", title=" + title + ", content=" + content + "]"; } }
4)编写Dao
package com.itheima.dao; import com.itheima.domain.Article; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; @Repository public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> { }
5)编写Service
package com.itheima.service; import com.itheima.domain.Article; public interface ArticleService { public void save(Article article); }
package com.itheima.service.impl; import com.itheima.dao.ArticleRepository; import com.itheima.domain.Article; import com.itheima.service.ArticleService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class ArticleServiceImpl implements ArticleService { @Autowired private ArticleRepository articleRepository; public void save(Article article) { articleRepository.save(article); } }
6) 配置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 "> <!-- 扫描Dao包,自动创建实例 --> <elasticsearch:repositories base-package="com.itheima.dao"/> <!-- 扫描Service包,创建Service的实体 --> <context:component-scan base-package="com.itheima.service"/> <!-- 配置elasticSearch的连接 --> <!-- 配置elasticSearch的连接 --> <elasticsearch:transport-client id="esClient" cluster-nodes="localhost:9301,localhost:9302,localhost:9303" cluster-name="my-elasticsearch"/> <!-- ElasticSearch模版对象 --> <bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate"> <constructor-arg name="client" ref="esClient"></constructor-arg> </bean> </beans>
7)配置实体
基于spring data elasticsearch注解配置索引、映射和实体的关系
package com.itheima.domain; 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; //@Document 文档对象 (索引信息、文档类型 ) @Document(indexName="blog3",type="article") public class Article { //@Id 文档主键 唯一标识 @Id //@Field 每个文档的字段配置(类型、是否分词、是否存储、分词器 ) @Field(store=true, index = false,type = FieldType.Integer) private Integer id; @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text) private String title; @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text) private String content; public Integer getId() { return id; } public void setId(Integer 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 "Article [id=" + id + ", title=" + title + ", content=" + content + "]"; } }
其中,注解解释如下: @Document(indexName="blob3",type="article"): indexName:索引的名称(必填项) type:索引的类型 @Id:主键的唯一标识 @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text) index:是否设置分词 analyzer:存储时使用的分词器 searchAnalyze:搜索时使用的分词器 store:是否存储 type: 数据类型
8)创建测试类SpringDataESTest
package com.itheima.test; import com.itheima.domain.Article; import com.itheima.service.ArticleService; import org.elasticsearch.client.transport.TransportClient; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataESTest { @Autowired private ArticleService articleService;
@Autowired
private ArticleRepository articleRepository;
@Autowired private TransportClient client; @Autowired private ElasticsearchTemplate elasticsearchTemplate; /**创建索引和映射*/ @Test public void createIndex(){ elasticsearchTemplate.createIndex(Article.class); elasticsearchTemplate.putMapping(Article.class); } /**测试保存文档*/ @Test public void saveArticle(){ Article article = new Article(); article.setId(1); article.setTitle("测试SpringData ElasticSearch"); article.setContent("Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 \n" + " Spring Data为Elasticsearch Elasticsearch项目提供集成搜索引擎"); articleService.save(article);
//把文档写入索引库
articleRepository.save(article); } }
三、Spring Data ElasticSearch的常用操作
1、增删改查方法测试
package com.itheima.service;
import com.itheima.domain.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface ArticleService {
//保存
public void save(Article article);
//删除
public void delete(Article article);
//查询全部
public Iterable<Article> findAll();
//分页查询
public Page<Article> findAll(Pageable pageable);
}
package com.itheima.service.impl;
import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
public void save(Article article) {
articleRepository.save(article);
}
public void delete(Article article) {
articleRepository.delete(article);
}
public Iterable<Article> findAll() {
Iterable<Article> iter = articleRepository.findAll();
return iter;
}
public Page<Article> findAll(Pageable pageable) {
return articleRepository.findAll(pageable);
}
}
package com.itheima.test; import com.itheima.domain.Article; import com.itheima.service.ArticleService; import org.elasticsearch.client.transport.TransportClient; 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.elasticsearch.core.ElasticsearchTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataESTest { @Autowired private ArticleService articleService; @Autowired private TransportClient client;
@Autowired
private ArticleRepository articleRepository;
@Autowired private ElasticsearchTemplate elasticsearchTemplate; /**创建索引和映射*/ @Test public void createIndex(){ elasticsearchTemplate.createIndex(Article.class); elasticsearchTemplate.putMapping(Article.class); } /**测试保存文档*/ @Test public void saveArticle(){ Article article = new Article(); article.setId(1); article.setTitle("测试SpringData ElasticSearch"); article.setContent("Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作"); articleService.save(article);
articleRepository.save(article); } /**测试保存*/ @Test public void save(){ Article article = new Article(); article.setId(2); article.setTitle("elasticSearch 3.0版本发布"); article.setContent("ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口"); articleRepository.save(article); } /**测试更新,根据id查询删除原有的,再添加文档*/ @Test public void update(){ Article article = new Article(); article.setId(2); article.setTitle("elasticSearch 3.0版本发布...更新"); article.setContent("ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口"); articleRepository.save(article); } /**测试删除*/ @Test public void delete(){ Article article = new Article(); article.setId(1001); articleRepository.delete(article);
articleRepository.deleteById(1L);
articleRepository.deleteAll();//删除全部文档 } /**批量插入*/ @Test public void save100(){ for(int i=1;i<=100;i++){ Article article = new Article(); article.setId(i); article.setTitle(i+"elasticSearch 3.0版本发布..,更新"); article.setContent(i+"ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口"); articleService.save(article); } }
@Test
public void findAll(){
Iterable<Article> articles = articleRepository.findAll();
articles.forEach(a->System.out.println(a));
}
@Test
public void findById(){
Optional<Article> optional = articleRepository.findById(1L);
Article article = optional.get();
System.out.println(article);
}
/**分页查询*/ @Test public void findAllPage(){ Pageable pageable = PageRequest.of(1,10); Page<Article> page = articleService.findAll(pageable); for(Article article:page.getContent()){ System.out.println(article); } } }
2、常用查询命名规则
3、查询方法测试
1)dao层实现
package com.itheima.dao; import com.itheima.domain.Article; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import java.util.List; public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> { //根据标题查询 List<Article> findByTitle(String condition); //根据标题查询(含分页) Page<Article> findByTitle(String condition, Pageable pageable); }
2)service层实现
public interface ArticleService { //根据标题查询 List<Article> findByTitle(String condition); //根据标题查询(含分页) Page<Article> findByTitle(String condition, Pageable pageable); }
package com.itheima.service.impl; import com.itheima.dao.ArticleRepository; import com.itheima.domain.Article; import com.itheima.service.ArticleService; 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.List; @Service public class ArticleServiceImpl implements ArticleService { @Autowired private ArticleRepository articleRepository; public List<Article> findByTitle(String condition) { return articleRepository.findByTitle(condition); } public Page<Article> findByTitle(String condition, Pageable pageable) { return articleRepository.findByTitle(condition,pageable); } }
3)测试代码
package com.itheima.test; import com.itheima.domain.Article; import com.itheima.service.ArticleService; import org.elasticsearch.client.transport.TransportClient; 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.elasticsearch.core.ElasticsearchTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class SpringDataESTest { @Autowired private ArticleService articleService; @Autowired private TransportClient client;
@Autowired
private ArticleRepository articleRepository;
@Autowired private ElasticsearchTemplate elasticsearchTemplate; /**条件查询*/ @Test public void findByTitle(){ String condition = "版本"; List<Article> articleList = articleService.findByTitle(condition); for(Article article:articleList){ System.out.println(article); } } /**条件分页查询*/ @Test public void findByTitlePage(){ String condition = "版本"; Pageable pageable = PageRequest.of(2,10); Page<Article> page = articleService.findByTitle(condition,pageable); for(Article article:page.getContent()){ System.out.println(article); } } }
4、使用Elasticsearch的原生查询对象进行查询。
@Test public void findByNativeQuery() { //创建一个SearchQuery对象 SearchQuery searchQuery = new NativeSearchQueryBuilder() //设置查询条件,此处可以使用QueryBuilders创建多种查询 .withQuery(QueryBuilders.queryStringQuery("备份节点上没有数据").defaultField("title")) //还可以设置分页信息 .withPageable(PageRequest.of(1, 5)) //创建SearchQuery对象 .build(); //使用模板对象执行查询 elasticsearchTemplate.queryForList(searchQuery, Article.class) .forEach(a-> System.out.println(a)); }