(3)elasticsearch集成到spingboot相关的操作

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值