ES的原生操作可以简单直观的查询一些东西,在实际的开发过程中与框架的整合可能才是我们比较关心的。今天这边文章主要是用spring data进行操作elasticsearch,详细如下:
一、添加依赖
<!--Elasticsearch相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
二、在配置文件中进行elasticsearch的相关配置
spring:
data:
elasticsearch:
repositories:
enabled: true
cluster-nodes: 127.0.0.1:9300 # es的连接地址及端口号,多个节点用逗号隔开
cluster-name: my-es # es集群的名称
三、java相关操作
spring操作elastic的时候有两种方式:ElasticsearchRepository和elasticsearchTemplate,大部分用的是ElasticsearchRepository,在进行高亮显示使用elasticsearchTemplate
(1)添加索引类
import java.io.Serializable;
import java.util.Date;
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;
/**
*
* String indexName();//索引库的名称,个人建议以项目的名称命名
String type() default "";//类型,个人建议以实体的名称命名
short shards() default 5;//默认分区数
short replicas() default 1;//每个分区默认的备份数
String refreshInterval() default "1s";//刷新间隔
String indexStoreType() default "fs";//索引文件存储类型
* 加上了@Document注解之后,默认情况下这个实体中所有的属性都会被建立索引、并且分词
* 不需要中文分词的字段设置成@Field(type = FieldType.Keyword)类型,
* 需要中文分词的设置成@Field(analyzer = "ik_max_word",type = FieldType.Text)类型
* @package com.eebbk.content.questions.youdao.nosql.elasticsearch.document
* @file EsQuestion.java
* @author lipf
* @date 2019年7月2日 上午8:42:36
* @version V 1.0
* select id,qid,body,answer,analysis,comment,knowledge,complexity,grade,subject,type
from questions_youdao_onlytext_10w a
*/
@Document(indexName = "que_10w", type = "question",shards = 1,replicas = 1)
public class EsQuestion implements Serializable{
private static final long serialVersionUID = -1L;
@Id
private Integer id;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String body;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String answer;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String analysis;
@Field(type = FieldType.Keyword)
private String subject;
@Field(type = FieldType.Keyword)
private String grade;
private String complexity;
private String knowledge;
private Integer sameFlag;
private Integer oprateFlag;
@Field(type = FieldType.Keyword)
private String type;
@Field(type = FieldType.Keyword)
private Date createTime;
@Field(type = FieldType.Keyword)
private Date updateTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public String getAnalysis() {
return analysis;
}
public void setAnalysis(String analysis) {
this.analysis = analysis;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public String getComplexity() {
return complexity;
}
public void setComplexity(String complexity) {
this.complexity = complexity;
}
public String getKnowledge() {
return knowledge;
}
public void setKnowledge(String knowledge) {
this.knowledge = knowledge;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public Integer getSameFlag() {
return sameFlag;
}
public void setSameFlag(Integer sameFlag) {
this.sameFlag = sameFlag;
}
public Integer getOprateFlag() {
return oprateFlag;
}
public void setOprateFlag(Integer oprateFlag) {
this.oprateFlag = oprateFlag;
}
}
(2)创建操作接口继承ElasticsearchRepository
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import com.macro.mall.tiny.nosql.elasticsearch.document.EsQuestion;
@Repository
public interface EsQuestionRepository extends ElasticsearchRepository<EsQuestion, Long> {
/**
* 搜索查询
* 在接口中直接指定查询方法名称便可查询,无需进行实现,
* 如题目表中有题干、答案和解析,直接定义以下查询,就可以对这三个字段进行全文搜索。
* @param Content 题干内容
* @param Answer 题目答案
* @param Solution 题目解析
* @param page 分页信息
* @return
*/
Page<EsQuestion> findByBodyOrAnswerOrAnalysis(String body, String answer, String analysis, Pageable page);
}
在用ElasticsearchRepository进行操作是,只需要写一个接口继承与ElasticsearchRepository,在这里是不用实现的,直接通过索引的字段名进行简单的查询,具体文章参考:https://www.jianshu.com/p/f23893b53e1e
(3)写相应的查询操作
【1】ES多字段查询(词条查询)
@ApiOperation(value = "ES多字段查询(词条查询)")
@RequestMapping(value = "/questionsearch/multiMatchQuery", method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<EsQuestion>> multiMatchQuery(@RequestParam(required = false) String keyword,
@RequestParam(required = false, defaultValue = "0") Integer pageNum,
@RequestParam(required = false, defaultValue = "5") Integer pageSize) {
Page<EsQuestion> esQuestionPage = esProductService.multiMatchQuery(keyword, pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(esQuestionPage));
}
@Override
public Page<EsQuestion> multiMatchQuery(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum, pageSize);
MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(keyword, "body","answer","analysis");
return questionRepository.search(multiMatchQuery, pageable);
}
【2】聚合查询
@ApiOperation(value = "ES聚合查询")
@RequestMapping(value = "/questionsearch/aggregationBuildersQuery", method = RequestMethod.GET)
@ResponseBody
public CommonResult<String> aggregationBuildersQuery(@RequestParam(required = false) String keyword,
@RequestParam(required = false, defaultValue = "0") Integer pageNum,
@RequestParam(required = false, defaultValue = "5") Integer pageSize) {
String esQuestionPage = esProductService.aggregationBuildersQuery(keyword, pageNum, pageSize);
return CommonResult.success(esQuestionPage);
}
@Override
public String aggregationBuildersQuery(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum, pageSize);
// 不查询任何结果
//nativeSearchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
//1.创建查询条件,也就是QueryBuild
MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();//设置查询所有,相当于不设置查询条件
//2.构建查询
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//2.0 设置QueryBuilder
nativeSearchQueryBuilder.withQuery(matchAllQuery);
//2.1设置搜索类型,默认值就是QUERY_THEN_FETCH,参考https://blog.csdn.net/wulex/article/details/71081042
nativeSearchQueryBuilder.withSearchType(SearchType.QUERY_THEN_FETCH);//指定索引的类型,只先从各分片中查询匹配的文档,再重新排序和排名,取前size个文档
//2.2指定索引库和文档类型
nativeSearchQueryBuilder.withIndices("que_10w").withTypes("question");//指定要查询的索引库的名称和类型,其实就是我们文档@Document中设置的indedName和type
//2.3指定聚合函数,本例中以某个字段分组聚合为例(可根据你自己的聚合查询需求设置)
//该聚合函数解释:计算该字段(假设为subject)在所有文档中的出现频次,并按照降序排名(常用于某个字段的热度排名)
TermsAggregationBuilder termsAggregation = AggregationBuilders.terms("term_subject").field("subject");
termsAggregation = termsAggregation.order(termsAggregation.order());
nativeSearchQueryBuilder.addAggregation(termsAggregation);
//2.4构建查询对象
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
//3.执行查询
AggregatedPage aggregatedPage = (AggregatedPage) questionRepository.search(nativeSearchQuery);
//4.根据聚合名称获取对应的聚合
StringTerms sources = (StringTerms) aggregatedPage.getAggregation("term_subject");
//获取查询到的桶
List<Bucket> buckets = sources.getBuckets();
StringBuffer stringBuffer = new StringBuffer("");
for (StringTerms.Bucket b : buckets) {
stringBuffer.append("科目名称:"+b.getKeyAsString()+"——数量:"+b.getDocCount()).append("\n");
System.out.println("科目名称:"+b.getKeyAsString()+"——数量:"+b.getDocCount());
}
return stringBuffer.toString();
}
【3】ES布尔查询(综合查询)
@ApiOperation(value = "ES布尔查询(综合查询)")
@RequestMapping(value = "/questionsearch/booleanQueSearch", method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<EsQuestion>> booleanQueSearch(@RequestParam(required = false) String keyword,
@RequestParam(required = false, defaultValue = "0") Integer pageNum,
@RequestParam(required = false, defaultValue = "5") Integer pageSize) {
Page<EsQuestion> esQuestionPage = esProductService.booleanQueSearch(keyword, pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(esQuestionPage));
}
@Override
public Page<EsQuestion> booleanQueSearch(String keyword, Integer pageNum, Integer pageSize) {
NativeSearchQueryBuilder nativeSearchQueryBuilder =new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("subject","化学"))
.must(QueryBuilders.matchQuery("body",keyword)));
Page<EsQuestion> newsEntityPage =questionRepository.search(nativeSearchQueryBuilder.build());
return newsEntityPage;
}
【4】其他有些查询
@Override
public Page<EsQuestion> searchQuestion(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum, pageSize);
//多字段查询
MultiMatchQueryBuilder matchPhraseQuery = QueryBuilders.multiMatchQuery(keyword, "body");
//精确匹配查询
//MatchPhraseQueryBuilder matchPhraseQuery = QueryBuilders.matchPhraseQuery("body", keyword);
//return questionRepository.search(matchPhraseQuery, pageable);
//按照ID进行查询
//IdsQueryBuilder addIds = QueryBuilders.idsQuery().addIds(keyword);
//模糊查询
//QueryStringQueryBuilder StringQuery = QueryBuilders.queryStringQuery(keyword).field("body");//左右模糊
return questionRepository.search(matchPhraseQuery,pageable);
}
【5】高亮查询
@Override
public AggregatedPage<EsQuestion> highlightQuery(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum, pageSize);
String preTag = "<font color='#dd4b39'>";//google的色值
String postTag = "</font>";
SearchQuery highlightQuery = new NativeSearchQueryBuilder().
withQuery(QueryBuilders.matchQuery("body", keyword)).
// withQuery(QueryBuilders.multiMatchQuery("answer", keyword)).
withHighlightFields(new HighlightBuilder.Field("body").preTags(preTag).postTags(postTag)
// ,new HighlightBuilder.Field("answer").preTags(preTag).postTags(postTag)
).build();
highlightQuery.setPageable(pageable);
// 不需要高亮直接return ideas
// AggregatedPage<EsQuestion> questions = elasticsearchTemplate.queryForPage(highlightQuery, EsQuestion.class);
// 高亮字段
AggregatedPage<EsQuestion> questions = elasticsearchTemplate.queryForPage(highlightQuery, EsQuestion.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<EsQuestion> chunk = new ArrayList<>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
EsQuestion que = new EsQuestion();
//name or memoe
HighlightField ideaTitle = searchHit.getHighlightFields().get("body");
if (ideaTitle != null) {
que.setBody(ideaTitle.fragments()[0].toString());
}
// HighlightField ideaContent = searchHit.getHighlightFields().get("ideaContent");
// if (ideaContent != null) {
// idea.setIdeaContent(ideaContent.fragments()[0].toString());
// }
chunk.add(que);
}
if (chunk.size() > 0) {
return new AggregatedPageImpl<>((List<T>) chunk);
}
return null;
}
});
return questions;
}
高亮查询成功后显示如下:
其他的详细查询可以参考文章:https://blog.csdn.net/topdandan/article/details/81436141