Elasticsearch的简单使用(实现中文词汇搜索并高亮显示-后端+前端)——java篇

简介

Elasticsearch中文文档
ELK:
ELK是ElasticsearchLogstashKibana三大开源架构的字母简称

Elasticsearch是基于Lucene、分布式、通过restful方式进行交互的进实时搜索平台框架。

Logstash是ELK的中英文数据流引擎,用于从不同目标收集不同格式数据,经过过滤后支持输出到不同的目的地。

Kibana是将Elasticsearch的数据展示出来,提供实时分析的功能。

下面的例子是实现中文词汇的搜索,并高亮显示。

使用

一、安装Elasticsearch

下载地址

下载后进行解压,然后双击bin目录下面的elasticsearch.bat即可启动成功,启动成功效果图:
在这里插入图片描述
访问上图的路径:127.0.0.1:9200
访问成功的界面如下图:
在这里插入图片描述

二、安装 Elasticsearch Head插件

下载地址

Elasticsearch-head 是一个基于node.js的前端工程,是elasticsearch的可视化客户端工具
下载解压后如下图操作:
在这里插入图片描述
打开后在命令窗口依次输入
npm install
npm run start

启动成功后的界面:
在这里插入图片描述
访问上面的地址——http://localhost:9100
访问后发现有跨域的问题,解决方法:
修改Elasticsearch中config目录下的elasticsearch.yml文件,在最下面加上跨域的代码
在这里插入图片描述

三、安装IK分词器插件

分词:把一段中文或者其他语言划分成一个个关键字,在搜索的时候,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每一个字看一个词,比如将“我爱学习”,会被分成“我” “爱” “学” “习”四个字,这不符合要求,需要安装中文分词器ik来解决这个问题。

下载地址

将下载解压后的文件放入到新的文件夹中命名为Ik,然后将Ik文件夹放入到Elasticsearch的plugin文件下面
重启Elasticsearch后,可以看到显示加载了Ik插件
在这里插入图片描述

四、代码编写

1、引入相关的pom文件

引入相关的pom文件并修改elasticsearch的版本号为下载的版本号

		<properties>
       	 	<elasticsearch.version>7.10.1</elasticsearch.version>
 		</properties>
    
<!--        导入fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
<!--        导入elasticsearch依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

2、配置类代码

@Configuration
public class ElasticSearchClientConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1",9200,"http")));
        return client;
    }

}

3、业务类代码

我写的是将数据库中的数据先拿出来,然后存入到Elasticsearch中,再进行搜索中文短语为高亮显示。

package com.tfjybj.dtc.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.tfjybj.dtc.search.model.ContentModel;
import com.tfjybj.dtc.search.service.abs.AbsElasticSearch;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
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.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @version 1.0
 * @Description 将数据库中的内容放入到es当中
 * @Author 刘一鸣
 * @CreateDate 2021/1/8 8:39
 * @UpdateUser
 * @UpdateDate
 * @UpdateRemark
 */
@Service
public class ElasticSearchImpl extends AbsElasticSearch {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private GlobalSearchImpl globalSearch;

    public List<String> parseContent() throws IOException {
        /**
         * @Describe 1、将数据库中所有数据都拿出来
         * @Author 刘一鸣
         * @Date 2021/1/9 8:51
         * @param
         * @Return java.util.List<java.lang.String>
         */
        List<String> contentList = globalSearch.queryAll();
        List<ContentModel> contentModelList = new ArrayList<>();
        for (int i = 0; i < contentList.size(); i++) {
            ContentModel contentModel = new ContentModel();
            contentModel.setContents(contentList.get(i));
            contentModelList.add(contentModel);
        }

        System.out.println(contentModelList);
        /**
         * @Describe 2、将从数据库拿出来的数据存入到es索引当中
         * @Author 刘一鸣
         * @Date 2021/1/9 8:52
         * @param []
         * @Return java.util.List<java.lang.String>
         */
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");

        for (int i = 0; i < contentList.size(); i++) {
            bulkRequest.add(
                    new IndexRequest("dtc_content")
                            .source(JSON.toJSONString(contentModelList.get(i)), XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return contentList;
    }

    /**
     * @param keyword, pageNo, pageSize
     * @Describe 3、获取这些数据实现搜索高亮
     * @Author 刘一鸣
     * @Date 2021/1/9 8:52
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     */
    public List<Map<String, Object>> searchPageHighlight(String keyword, int pageNo, int pageSize) throws IOException {

        if (pageNo <= 1) {
            pageNo = 1;
        }
        //条件搜索
        SearchRequest searchRequest = new SearchRequest("dtc_content");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);
        // 精准匹配(支持中文词语搜索)
        sourceBuilder.query(QueryBuilders.boolQuery().should(QueryBuilders.matchPhraseQuery("contents", keyword)));

        //QueryBuilders.boolQuery()
        //        .should(QueryBuilders.matchQuery("contents",keyword)
        //                .analyzer("ik_max_word")
        //                .operator(Operator.OR));

        //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("contents",keyword);
        //sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        // 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("contents");
        //  关闭多个高亮显示
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);
        // 执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {

            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField title = highlightFields.get("contents");
            //原来的结果
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
            //解析高亮的字段,将原来的字段换成我们高亮的字段即可
            if (title != null) {
                org.elasticsearch.common.text.Text[] fragments = title.fragments();
                String n_title = "";
                for (Text text : fragments) {
                    n_title += text;
                }
                //将高亮替换为原来的内容
                sourceAsMap.put("contents", n_title);
            }
            list.add(sourceAsMap);
        }
        return list;
    }

}

4、model类代码

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ContentModel {
  private String contents;
}

5、controller类代码

  /**
    * @Describe 高亮显示
    * @Author 刘一鸣
    * @Date 2021/1/9 8:56
    * @param keyword, pageNo, pageSize
    * @Return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
    */
    @ApiOperation(value = "查询es索引中的内容并高亮显示")
    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable("keyword") String keyword,
                                           @PathVariable("pageNo") int pageNo,
                                           @PathVariable("pageSize") int pageSize) throws IOException {
        return elasticSearch.searchPageHighlight(keyword,pageNo,pageSize);
    }

6、前端书写

书写好前端的样式后,前端调后端的search接口即可。
这里重点写一下v-html在element-ui组件中el-table表格中的用法

  <el-table :data="results">
     <el-table-column prop="contents">
             <template slot-scope="scope">
               <div v-html="scope.row.contents"></div>
             </template>
      </el-table-column>
  </el-table>
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值