国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[Spring Boot]12 ElasticSearch實(shí)現(xiàn)分詞搜索功能

這篇具有很好參考價(jià)值的文章主要介紹了[Spring Boot]12 ElasticSearch實(shí)現(xiàn)分詞搜索功能。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、前言

我們?cè)谑褂盟阉鞴δ艿臅r(shí)候,有時(shí),為了使搜索的結(jié)果更多更廣,比如搜索字符串“領(lǐng)導(dǎo)力”,希望有這些組合的結(jié)果(領(lǐng)導(dǎo)力、領(lǐng)導(dǎo)、領(lǐng)、導(dǎo)、力)都要能夠全部展示出來。
這里我們引入ElasticSearch結(jié)合分詞插件,來實(shí)現(xiàn)這樣的搜索功能。

二、搜索功能的需求

比如:一款app需要對(duì)“課程”進(jìn)行關(guān)鍵字搜索。
首先:課程包含的信息有:標(biāo)題、子標(biāo)題、講師、簡介、所屬標(biāo)簽、封面圖片、講數(shù)等等。
搜索的需求為:輸入關(guān)鍵字,要能分詞匹配課程的這些信息:標(biāo)題、子標(biāo)題、講師、所屬標(biāo)簽。
搜索需求:搜索結(jié)果的原型圖如下圖所示:
[Spring Boot]12 ElasticSearch實(shí)現(xiàn)分詞搜索功能
紅色高亮為搜索結(jié)果,覆蓋了標(biāo)題、子標(biāo)題、所屬標(biāo)簽、講師名稱,并能進(jìn)行分詞搜索且關(guān)鍵字高亮。

三、需求開發(fā)

1、服務(wù)器安裝ElasticSearch和IK分詞器

參考鏈接: [Linux安裝軟件詳解系列]05 安裝ElasticSearch和IK分詞器

2、需求開發(fā)

1)pom.xml引入jar包:
 <!--elasticsearch-->
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
 </dependency>       
2)yml增加配置
  // 安裝ElasticSearch時(shí)對(duì)應(yīng)的信息
  elasticsearch:
    rest:
      uris: http://ip:9200
      username: test
      password: 123456
3)配置類ElasticsearchConfig

ElasticsearchConfig:

package com.test.api.config;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
/**
 * es 配置
 *
 * @author /
 */
@EnableElasticsearchRepositories(basePackages = {"com.test.bi.*.repository"})
@Configuration
public class ElasticsearchConfig {
    @Value("${spring.elasticsearch.rest.uris}")
    private String hostAndPort;
    @Value("${spring.elasticsearch.rest.username}")
    private String username;
    @Value("${spring.elasticsearch.rest.password}")
    private String password;
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(hostAndPort)
                .withBasicAuth(username, password)
                .build();
        return RestClients.create(clientConfiguration).rest();
    }
}
4)工具類ElasticsearchUtil

ElasticsearchUtil:

package com.test.common.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * es 工具類
 *
 * @author /
 */
@Slf4j
@Component
public class ElasticsearchUtil {
    @Resource
    private RestHighLevelClient restHighLevelClient;
    /**
     * 普通查詢
     *
     * @param index               索引名稱
     * @param searchSourceBuilder 查詢條件構(gòu)建
     * @param resultClass         類
     * @param currentPage         當(dāng)前頁 分頁的頁碼,不是es 的
     * @param size                每頁顯示數(shù)據(jù)
     */
    public <T> PageInfo<T> page(String index, SearchSourceBuilder searchSourceBuilder, Class<T> resultClass,
                                int currentPage, int size, List<String> highFields) {
        SearchRequest request = new SearchRequest(index);
        // 高亮字段設(shè)置
        if (CollectionUtil.isNotEmpty(highFields)) {
            buildHighLight(searchSourceBuilder, highFields);
        }
        // 分頁
        int num = (currentPage - 1) * size;
        searchSourceBuilder.from(num)
                .size(size);
        request.source(searchSourceBuilder);
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert response != null;
        return analysisResponse(response, resultClass, currentPage, size, highFields);
    }

    /**
     * 解析es 查詢結(jié)果
     *
     * @param response    返回
     * @param resultClass 轉(zhuǎn)換成對(duì)象類
     */
    private <T> PageInfo<T> analysisResponse(SearchResponse response, Class<T> resultClass, int currentPage, int size, List<String> highFields) {
        SearchHit[] searchHits = response.getHits().getHits();
        List<T> retList = new ArrayList<>(searchHits.length);
        for (SearchHit searchHit : searchHits) {
            String strJson = searchHit.getSourceAsString();
            T t = JSONUtil.toBean(strJson, resultClass);
            try {
                setId(resultClass, t, String.valueOf(searchHit.getId()));
            } catch (Exception e) {
                log.info("es 查詢數(shù)據(jù)設(shè)置主鍵id值異常", e);
            }
            // 高亮字段設(shè)置后,組織結(jié)果,es 結(jié)果建議與java 對(duì)象 名稱一直,基本要求
            if (!CollectionUtils.isEmpty(highFields)) {
                Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
                HighlightField highlightField;
                for (String field : highFields) {
                    highlightField = highlightFieldMap.get(field);
                    if (highlightField != null) {
                        // 獲取指定字段的高亮片段
                        Text[] fragments = highlightField.getFragments();
                        // 將這些高亮片段拼接成一個(gè)完整的高亮字段
                        StringBuilder builder = new StringBuilder();
                        for (Text text : fragments) {
                            builder.append(text);
                        }
                        // 設(shè)置到實(shí)體類中
                        setValue(resultClass, t, builder.toString(), field);
                    }
                }
            }
            retList.add(t);
        }
        long totalNum = response.getHits().getTotalHits();
        PageInfo<T> pageVo = new PageInfo<>();
        pageVo.setPageNum(currentPage);
        pageVo.setPageSize(size);
        pageVo.setTotal(totalNum);
        pageVo.setList(retList);
        return pageVo;
    }

    /**
     * 對(duì)象id 為空時(shí),給id 賦值
     *
     * @param resultClass 類
     * @param t           對(duì)象
     * @param id          主鍵id 的值
     */
    @SneakyThrows
    private <T> void setId(Class<T> resultClass, T t, Object id) {
        Field field = ReflectionUtils.findField(resultClass, "id");
        if (null != field) {
            field.setAccessible(true);
            Object object = ReflectionUtils.getField(field, t);
            if (object == null) {
                Method method = resultClass.getMethod("setId", String.class);
                ReflectionUtils.invokeMethod(method, t, id);
            }
        }
    }

    /**
     * 指定字段賦值
     *
     * @param resultClass 類
     * @param t           對(duì)象
     * @param fieldValue  字段名
     * @param fieldName   字段值
     */
    @SneakyThrows
    private <T> void setValue(Class<T> resultClass, T t, Object fieldValue, String fieldName) {
        Field field = ReflectionUtils.findField(resultClass, fieldName);
        if (null != field) {
            field.setAccessible(true);
            String methodName = "set".concat(captureName(fieldName));
            Method method = resultClass.getMethod(methodName, String.class);
            ReflectionUtils.invokeMethod(method, t, fieldValue);
        }
    }

    /**
     * 進(jìn)行字母的ascii編碼前移,效率要高于截取字符串進(jìn)行轉(zhuǎn)換的操作
     *
     * @param str /
     */
    private String captureName(String str) {
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    /**
     * 設(shè)置高亮
     *
     * @param searchSourceBuilder /
     * @param fields              高亮字段
     */
    private void buildHighLight(SearchSourceBuilder searchSourceBuilder, List<String> fields) {
        // 設(shè)置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        fields.forEach(highlightBuilder::field);
        highlightBuilder.preTags("<em>");
        highlightBuilder.postTags("</em>");
        // 給請(qǐng)求設(shè)置高亮
        searchSourceBuilder.highlighter(highlightBuilder);
    }

    /**
     * es Scroll 深分頁 定義bean
     */
    @AllArgsConstructor
    @Data
    public class ScrollPageBean<T> {
        private String scrollId;
        private PageInfo<T> scrollPage;
    }
}
5)返回的數(shù)據(jù)BO封裝
package com.test.bi.bo.course;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
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;

import java.io.Serializable;

/**
 * 課程-搜索
 *
 * @author /
 */
@Document(indexName = "course_es", type = "_doc", replicas = 0)
@Data
public class CourseEsDTO implements Serializable {

    @ApiModelProperty(value = "課程編號(hào)")
    @Id
    private String id;

    @ApiModelProperty(value = "標(biāo)題")
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;

    @ApiModelProperty(value = "講師名稱")
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String teacherName;

    @ApiModelProperty(value = "子標(biāo)題")
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String subtitle;

    @ApiModelProperty(value = "所屬標(biāo)簽名稱列表")
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String labelName;

    @ApiModelProperty(value = "封面圖片")
    @Field(type = FieldType.Text)
    private String pic;

    @ApiModelProperty(value = "講數(shù)")
    @Field(type = FieldType.Integer)
    private Integer count;
}
6)保存數(shù)據(jù)至ElasticSearch

保存數(shù)據(jù)到ElasticSearch中,通常有兩種方式:一種是通過ElasticsearchRepository 接口,另一種是通過ElasticsearchTemplate接口,我們使用ElasticsearchRepository接口來實(shí)現(xiàn)。
實(shí)現(xiàn)接口:CourseEsRepository,可以放在mapper里面。

package com.test.bi.mapper;

import com.test.bi.bo.course.CourseEsDTO;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

/**
 * 課程-搜索
 *
 * @author /
 */
@Repository
public interface CourseEsRepository extends ElasticsearchRepository<CourseEsDTO, String> {
}

保存數(shù)據(jù):

@Resource
private CourseEsRepository courseEsRepository;

@Override
public void saveCourseEs() {
    try {
        courseEsRepository.deleteAll();
        // 從庫中取數(shù)據(jù)
        List<CourseEsDTO> list = courseMapper.getCourseEsList();
        if (IterUtil.isNotEmpty(list)) {
            courseEsRepository.saveAll(list);
        }
    } catch (Exception e) {
        log.error("es error:{}", e.getMessage());
    }
}
7)根據(jù)關(guān)鍵字搜索,分頁返回?cái)?shù)據(jù)
@Override
public PageInfo<CourseEsDTO> getCourseEs(String keywords, Integer pageNum, Integer pageSize) {
    // 使用best_fields模式, 對(duì)多個(gè)字段進(jìn)行查詢
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    String[] queryFields = {"teacherName", "subtitle", "labelName"
    };
    QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keywords, queryFields)
            .field("name", 2F)
            .tieBreaker(0.3F);
    searchSourceBuilder.query(queryBuilder);
    // 高亮
    List<String> highFields = ListUtil.toList(queryFields);
    highFields.add("name");
    // 分頁返回?cái)?shù)據(jù)
    return elasticsearchUtil.page("course_es", searchSourceBuilder, CourseEsDTO.class, pageNum,
            pageSize, highFields);
}

8)總結(jié)

總結(jié)一下,就是通過一個(gè)小的需求例子,很好地實(shí)現(xiàn)了分詞搜索,并且要能夠高亮顯示關(guān)鍵字。
具體的ElasticSearch和對(duì)應(yīng)iK分詞的代碼功能,我就不一一展開了,可以去官方查看,這里只是演示一下實(shí)現(xiàn)搜索功能的簡單過程,希望對(duì)大家有所幫助。文章來源地址http://www.zghlxwxcb.cn/news/detail-436457.html

到了這里,關(guān)于[Spring Boot]12 ElasticSearch實(shí)現(xiàn)分詞搜索功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot進(jìn)階(19):探索ElasticSearch:如何利用Spring Boot輕松實(shí)現(xiàn)高效數(shù)據(jù)搜索與分析

    Spring Boot進(jìn)階(19):探索ElasticSearch:如何利用Spring Boot輕松實(shí)現(xiàn)高效數(shù)據(jù)搜索與分析

    ????????ElasticSearch是一款基于Lucene的開源搜索引擎,具有高效、可擴(kuò)展、分布式的特點(diǎn),可用于全文搜索、日志分析、數(shù)據(jù)挖掘等場景。Spring Boot作為目前最流行的微服務(wù)框架之一,也提供了對(duì)ElasticSearch的支持。本篇文章將介紹如何在Spring Boot項(xiàng)目中整合ElasticSearch,并展

    2024年02月11日
    瀏覽(23)
  • spring boot使用elasticsearch分詞,排序,分頁,高亮簡單示例

    spring boot使用elasticsearch分詞,排序,分頁,高亮簡單示例

    記,寫一個(gè)簡單的es分詞demo,es版本6.8.12 如果使用es7有些方法可能會(huì)有所改變,請(qǐng)參考7的文檔 es安裝教程:http://t.csdn.cn/BSh12 怎么簡單怎么來 商品名稱加了 @Field(type = FieldType.Text, analyzer = “ik_max_word”) 會(huì)自動(dòng)分詞 分頁處理 3.2.1 分詞 當(dāng)輸入衣服鞋子的時(shí)候會(huì)將分

    2024年02月08日
    瀏覽(23)
  • 《Spring Boot 實(shí)戰(zhàn)派》--13.集成NoSQL數(shù)據(jù)庫,實(shí)現(xiàn)Elasticsearch和Solr搜索引擎

    《Spring Boot 實(shí)戰(zhàn)派》--13.集成NoSQL數(shù)據(jù)庫,實(shí)現(xiàn)Elasticsearch和Solr搜索引擎

    ?????????關(guān)于搜索引擎 我們很難實(shí)現(xiàn) Elasticseach 和 Solr兩大搜索框架的效果;所以本章針對(duì)兩大搜索框架,非常詳細(xì)地講解 它們的原理和具體使用方法, 首先 介紹什么是搜索引擎 、如何用 MySQL實(shí)現(xiàn)簡單的搜索引擎,以及Elasticseach 的 概念和接口類; 然后介紹Elasticseach

    2023年04月09日
    瀏覽(25)
  • Spring Boot 集成 ElasticSearch:實(shí)現(xiàn)模糊查詢、批量 CRUD、排序、分頁和高亮功能

    Spring Boot 集成 ElasticSearch:實(shí)現(xiàn)模糊查詢、批量 CRUD、排序、分頁和高亮功能

    文章來源:https://blog.csdn.net/qq_52355487/article/details/123805713 在pom.xml里加入如下依賴 非常重要:檢查依賴版本是否與你當(dāng)前所用的版本是否一致,如果不一致,會(huì)連接失??! 1.創(chuàng)建、判斷存在、刪除索引 2.對(duì)文檔的CRUD 創(chuàng)建文檔: 注意:如果添加時(shí)不指定文檔ID,他就會(huì)隨機(jī)生成

    2024年02月04日
    瀏覽(26)
  • spring boot 3使用 elasticsearch 提供搜索建議

    spring boot 3使用 elasticsearch 提供搜索建議

    用戶輸入內(nèi)容,快速返回建議,示例效果如下 spring boot 3 elasticsearch server 7.17.4 spring data elasticsearch 5.0.1 elasticsearch-java-api 8.5.3 為了啟動(dòng)時(shí)候自己創(chuàng)建相關(guān)的index,以及存儲(chǔ)搜索內(nèi)容 數(shù)據(jù)導(dǎo)入時(shí)候,因?yàn)橛袛?shù)據(jù)格式要求,必須使用實(shí)體類進(jìn)行寫入

    2024年02月12日
    瀏覽(18)
  • Spring boot 2.3.12集成ElasticSearch7.6.2并進(jìn)行CRUD

    Spring boot 2.3.12集成ElasticSearch7.6.2并進(jìn)行CRUD

    本篇博客主要講解Spring boot 2.3.12集成ElasticSearch7.6.2并進(jìn)行CRUD操作。其它版本的spring boot集成ElasticSearch類似,只需要具體各自的版本是否匹配。通過本篇博客能夠成功集成ElasticSearch并進(jìn)行CRUD操作,適合剛接觸ElasticSearch需要進(jìn)行簡單CRUD操作的讀者。 在集成ElasticSearch之前需要明

    2023年04月08日
    瀏覽(21)
  • 從零開始學(xué)Spring Boot系列-前言

    在數(shù)字化和信息化的時(shí)代,Java作為一種成熟、穩(wěn)定且廣泛應(yīng)用的編程語言,已經(jīng)成為構(gòu)建企業(yè)級(jí)應(yīng)用的首選。而在Java生態(tài)系統(tǒng)中,Spring框架無疑是其中最為耀眼的一顆明星。它提供了全面的編程和配置模型,用于構(gòu)建企業(yè)級(jí)應(yīng)用。隨著Spring Boot的出現(xiàn),這一框架變得更加易于

    2024年02月22日
    瀏覽(34)
  • Elasticsearch搜索功能的實(shí)現(xiàn)(五)-- 實(shí)戰(zhàn)

    Elasticsearch搜索功能的實(shí)現(xiàn)(五)-- 實(shí)戰(zhàn)

    實(shí)戰(zhàn)環(huán)境 elastic search 8.5.0 + kibna 8.5.0 + springboot 3.0.2 + spring data elasticsearch 5.0.2 + jdk 17 實(shí)現(xiàn)效果圖片: 實(shí)際執(zhí)行的DSL語句: 注意: 當(dāng)指定排序條件時(shí) _score 會(huì)被置空 加權(quán)前效果: 加權(quán)后效果: DSL 語句:

    2023年04月18日
    瀏覽(22)
  • Elasticsearch-queryStringQuery進(jìn)行不分詞搜索

    queryStringQuery 會(huì)對(duì)查詢的先進(jìn)行分詞,然后在進(jìn)行匹配。 但是如果要讓它已空格分割,分割后每個(gè)詞進(jìn)行精確查詢呢 // 一般需要精確查詢的字段,在存儲(chǔ)的時(shí)候都不建議分詞。但是已經(jīng)分詞了,還想精確精確查詢,使用queryStringQuery,在需要精確查詢的詞語外面使用雙

    2024年02月02日
    瀏覽(25)
  • Elasticsearch 全文搜索引擎 ---- IK分詞器

    Elasticsearch 全文搜索引擎 ---- IK分詞器

    ????????原理:分詞的原理:二叉樹? ? ? ? ? ????????首先講一下為什么要出這個(gè)文章,前面我們講過分詞方法: 中文分詞搜索 pscws (感興趣的同學(xué)可以去爬樓看一下),那為什么要講 IK分詞 ?最主要的原因是:pscws分詞 顆粒度 不如IK分詞的顆粒度高,現(xiàn)在的需求

    2024年02月10日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包