elasticsearch官方更新的版本速度太快,而springboot上的胶水代码更新的速度太慢,最关键的是elasticsearch每个版本的基础api都有变化,因此这里提示版本问题,不然就踩坑吧,我也是在6.0.0只有发现根本无法使用springboot上提供的spring-boot-starter-data-elasticsearch,当然如果你只是使用spring-data-elasticsearch的话是可以直接使用最新版本的。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.1.RELEASEversion>
<relativePath/>
parent>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
elasticsearch-2.4.4下载地址
https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.4.4/elasticsearch-2.4.4.tar.gz
elasticsearch-analysis-ik1.10.4和上面的版本相对应的插件下载地址
https://github.com/medcl/elasticsearch-analysis-ik/tree/v1.10.4
spring data elsaticsearch提供了三种构建查询模块的方式:
1. 基本的增删改查:继承spring data提供的接口就默认提供
2. 接口中声明方法:无需实现类,spring data根据方法名,自动生成实现类,方法名必须符合一定的规则(这里还扩展出一种忽略方法名,根据注解的方式查询),样例参考:ArticleSearchRepository
接口只要继承 ElasticsearchRepository 类即可。默认会提供很多实现,比如 CRUD 和搜索相关的实现。类似于 JPA 读取数据,是使用 CrudRepository 进行操作 ES 数据。支持的默认方法有: count(), findAll(), findOne(ID), delete(ID), deleteAll(), exists(ID), save(DomainObject), save(Iterable)。
另外可以看出,接口的命名是遵循规范的。常用命名规则如下:
关键字 方法命名
And findByNameAndPwd
Or findByNameOrSex
Is findById
Between findByIdBetween
Like findByNameLike
NotLike findByNameNotLike
OrderBy findByIdOrderByXDesc
Not findByNameNot
依赖的文件上面已经加了,直接看代码
spring:
data:
elasticsearch: #ElasticsearchProperties
cluster-name: elasticsearch #默认即为elasticsearch
cluster-nodes: 192.168.0.91:9300 #配置es节点信息,逗号分隔,如果没有指定,则启动ClientNode
Java对应的elasticsearch映射文件类型
package bamboo;
import java.io.Serializable;
import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;
/**
* Created by xialeme on 2017/11/30.
*/
@Document(indexName="article_index",type="article",shards=5,replicas=1,indexStoreType="fs",refreshInterval="-1")
public class Article implements Serializable{
/**
*
*/
private static final long serialVersionUID = 551589397625941750L;
@Id
private Long id;
/**标题*/
// @Field(index= FieldIndex.not_analyzed,store=true,type=FieldType.String)
private String title;
/**摘要*/
private String abstracts;
/**内容*/
private String content;
/**发表时间*/
@Field(format=DateFormat.date_time,index=FieldIndex.not_analyzed,store=true,type= FieldType.Object)
private Date postTime;
/**点击率*/
private Long clickCount;
//setters and getters
//toString
public Article() {
}
public Article(Long id, String title, String abstracts, String content, Date postTime, Long clickCount) {
this.id = id;
this.title = title;
this.abstracts = abstracts;
this.content = content;
this.postTime = postTime;
this.clickCount = clickCount;
}
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 getAbstracts() {
return abstracts;
}
public void setAbstracts(String abstracts) {
this.abstracts = abstracts;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getPostTime() {
return postTime;
}
public void setPostTime(Date postTime) {
this.postTime = postTime;
}
public Long getClickCount() {
return clickCount;
}
public void setClickCount(Long clickCount) {
this.clickCount = clickCount;
}
@Override
public String toString() {
return "Article{" +
"id=" + id +
", title='" + title + '\'' +
", abstracts='" + abstracts + '\'' +
", content='" + content + '\'' +
", postTime=" + postTime +
", clickCount=" + clickCount +
'}';
}
}
ArticleSearchRepository .java
只需要继承ElasticsearchRepository泛型,基础的CRUD不用代码就可以直接使用,如果有简单的特殊需求则根据上面提到的命名规则定义好接口名称就能使用。
但如果是聚合特殊数据则需要自行使用ElasticsearchTemplate实现具体的调用逻辑。
package bamboo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
/**
* //泛型的参数分别是实体类型和主键类型
* Created by xialeme on 2017/11/30.
*/
public interface ArticleSearchRepository extends ElasticsearchRepository{
public List findByTitle(String title);
/**
* AND 语句查询
*
* @param tile
* @param clickCount
* @return
*/
List findByTitleAndClickCount(String tile, Integer clickCount);
/**
* OR 语句查询
*
* @param tile
* @param clickCount
* @return
*/
List findByTitleOrClickCount(String tile, Integer clickCount);
/**
* 查询文章内容分页
*
* 等同于下面代码
* @Query("{\"bool\" : {\"must\" : {\"term\" : {\"content\" : \"?0\"}}}}")
* Page findByContent(String content, Pageable pageable);
*
* @param content
* @param page
* @return
*/
Page findByContent(String content, Pageable page);
/**
* NOT 语句查询
*
* @param content
* @param page
* @return
*/
Page findByContentNot(String content, Pageable page);
/**
* LIKE 语句查询
*
* @param content
* @param page
* @return
*/
Page findByContentLike(String content, Pageable page);
}
ArticleSearchRepositoryTest.java
查询实例
import bamboo.Application;
import bamboo.Article;
import bamboo.ArticleSearchRepository;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.*;
/**
*
* Created by xialeme on 2017/11/30.
* spring data elsaticsearch提供了三种构建查询模块的方式:
1. 基本的增删改查:继承spring data提供的接口就默认提供
2. 接口中声明方法:无需实现类,spring data根据方法名,自动生成实现类,方法名必须符合一定的规则(这里还扩展出一种忽略方法名,根据注解的方式查询),样例参考:ArticleSearchRepository
3. 自定义repository:在实现类中注入elasticsearchTemplate,实现上面两种方式不易实现的查询(例如:聚合、分组、深度翻页等)
*
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
//@SpringApplicationConfiguration(classes=Application.class)
@SpringBootTest(classes= Application.class)
public class ArticleSearchRepositoryTest {
@Autowired
private ArticleSearchRepository articleSearchRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
/*测试自动创建mapping
*curl '192.168.0.91:9200/_cat/indices?v'
* curl -XGET "http://192.168.0.91:9200/article_index/_mapping?pretty"
*
* */
@Test
public void test(){
System.out.println("演示初始化");
}
/*
*保存测试
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testSave(){
Article article=new Article(3L,"srpignMVC教程","srpignMVC","srpignMVC入门到放弃",new Date(),22L);
Article article1=new Article(4L,"srpig教程","spring","spring入门到放弃",new Date(),20L);
Article article2=new Article(5L,"srpigCloud教程","springCloud","springCloud入门到放弃",new Date(),20L);
Article article3=new Article(6L,"java教程","java","java入门到放弃",new Date(),120L);
Article article4=new Article(7L,"php教程","php","php入门到放弃",new Date(),160L);
// articleSearchRepository.save(article);
// articleSearchRepository.save(article1);
// articleSearchRepository.save(article2);
// articleSearchRepository.save(article3);
// articleSearchRepository.save(article4);
Article article8=new Article(8L,"mysql教程","mysql","mysql入门到放弃",new Date(),460L);
Article article9=new Article(9L,"redis教程","redis","redis入门到放弃",new Date(),60L);
Article article10=new Article(10L,"c教程","c","c教程入门到放弃",new Date(),600L);
//bulk index 批量方式插入
List sampleEntities = Arrays.asList( article10);
articleSearchRepository.save(sampleEntities);
}
/*
*获取所有测试
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testFetchAll(){
for (Article article : articleSearchRepository.findAll()) {
System.out.println(article.toString());
}
}
/*
*精确查找
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testFetchArticle(){
for (Article article : articleSearchRepository.findByTitle("srpignboot教程")) {
System.out.println(article.toString());
}
}
/*
*分页测试
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testPage(){
List list;
// list=articleSearchRepository.findByTitleAndClickCount("教程",20 );//and
// list=articleSearchRepository.findByTitleOrClickCount("教程",20 );//or
// 分页参数:分页从0开始,clickCount倒序
Pageable pageable = new PageRequest(0, 5, Sort.Direction.DESC,"clickCount");
Page pageageRsutl=articleSearchRepository.findByContent("入门",pageable );
System.out.println("总页数"+pageageRsutl.getTotalPages());
list= pageageRsutl.getContent();//结果
for (Article article : list) {
System.out.println(article.toString());
}
}
/*
*其他查找
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testDls(){
List list;
// 创建搜索 DSL:多条件搜索
/* 搜索模式: boolQuery */
Pageable pageable = new PageRequest(0, 5);//分页
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
.add(boolQuery().should(QueryBuilders.matchQuery("content", "教程")),
ScoreFunctionBuilders.weightFactorFunction(100))
.add(boolQuery().should(QueryBuilders.matchQuery("clickCount", 20)),
ScoreFunctionBuilders.weightFactorFunction(1000));
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withPageable(pageable)
.withQuery(functionScoreQueryBuilder).build();
System.out.println("\n search DSL = \n " + searchQuery.getQuery().toString());
Page searchPageResults = articleSearchRepository.search(searchQuery);
list= searchPageResults.getContent();//结果
for (Article article : list) {
System.out.println(article.toString());
}
}
/*
*聚合查询测试
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void testScore(){
List list;
// 创建搜索 DSL 查询:weightFactorFunction是评分函数,官网的控制相关度中有详细讲解价格,地理位置因素
/* 搜索模式 */
String SCORE_MODE_SUM = "sum"; // 权重分求和模式
Float MIN_SCORE = 10.0F; // 由于无相关性的分值默认为 1 ,设置权重分最小值为 10
// Function Score Query
Pageable pageable = new PageRequest(0, 5);
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
.add(boolQuery().should(QueryBuilders.matchQuery("content", "教程")),
ScoreFunctionBuilders.weightFactorFunction(1000))
.add(boolQuery().should(QueryBuilders.matchQuery("clickCount", 20)),
ScoreFunctionBuilders.weightFactorFunction(1000)).
scoreMode(SCORE_MODE_SUM).setMinScore(MIN_SCORE);//分值模式设置为:求和,
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withPageable(pageable).build();
System.out.println("\n search DSL = \n " + searchQuery.getQuery().toString());
Page searchPageResults = articleSearchRepository.search(searchQuery);
list= searchPageResults.getContent();//结果
for (Article article : list) {
System.out.println(article.toString());
}
}
/*
*elasticsearchTemplate自定义查询:提交时间倒叙
*elasticsearchTemplate
* curl '192.168.0.91:9200/article_index/article/_search?q=*&pretty'
*/
@Test
public void etmTest() {
//查询关键字
String word="c入门";
// 分页设置,postTime倒序
Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC,"postTime");
SearchQuery searchQuery;
//0.使用queryStringQuery完成单字符串查询queryStringQuery(word, "title")
//1.multiMatchQuery多个字段匹配 .operator(MatchQueryBuilder.Operator.AND)多项匹配使用and查询即完全匹配都存在才查出来
//searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery(word, "title", "content").operator(MatchQueryBuilder.Operator.AND)).withPageable(pageable).build();
//2.多条件查询:title和content必须包含word=“XXX”且clickCount必须大于200的以postTime倒序分页结果
word="教程";
searchQuery = new NativeSearchQueryBuilder().withQuery(boolQuery().must(multiMatchQuery(word, "title", "content").operator(MatchQueryBuilder.Operator.AND)).must(rangeQuery("clickCount").gt(200))).withPageable(pageable).build();
List list= elasticsearchTemplate.queryForList(searchQuery, Article.class);
for (Article article : list) {
System.out.println(article.toString());
}
}
}
https://github.com/BambooZhang/springboot-study/tree/master/springboot-Spring-data-elasticsearch