zoukankan      html  css  js  c++  java
  • springboot集成elasticsearch

    添加pom

    <!--elasticsearch-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
            <dependency>
                <groupId>io.searchbox</groupId>
                <artifactId>jest</artifactId>
                <version>5.3.3</version>
            </dependency>
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>x-pack-transport</artifactId>
                <version>5.5.0</version>
            </dependency>

    完整的pom

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>zhong</artifactId>
            <groupId>com.zh</groupId>
            <version>1.0</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>zhong-search</artifactId>
        <packaging>jar</packaging>
        <properties>
            <elasticsearch.version>5.6.10</elasticsearch.version>
        </properties>
        <dependencies>
            <!--公共模块-->
            <dependency>
                <groupId>com.zh</groupId>
                <artifactId>zhong-common-api</artifactId>
                <version>${zhong.version}</version>
            </dependency>
            <dependency>
                <groupId>com.zh</groupId>
                <artifactId>zhong-common-core</artifactId>
                <version>${zhong.version}</version>
            </dependency>
            <!--配置中心客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <!--web 模块-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <exclusions>
                    <!--排除tomcat依赖-->
                    <exclusion>
                        <artifactId>spring-boot-starter-tomcat</artifactId>
                        <groupId>org.springframework.boot</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!--undertow容器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-undertow</artifactId>
            </dependency>
            <!--elasticsearch-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
            <dependency>
                <groupId>io.searchbox</groupId>
                <artifactId>jest</artifactId>
                <version>5.3.3</version>
            </dependency>
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>x-pack-transport</artifactId>
                <version>5.5.0</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

    bootstrap.yml配置

    spring:
       data:
          elasticsearch:
             cluster‐name: my-application
             cluster‐nodes: 192.168.1.107:9300

    添加entity实体

    package com.zh.search.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.*;
    
    import java.time.LocalDateTime;
    import java.util.Date;
    
    /**
     * @Auther: suruozhong
     * @Date: 2019/11/14 17:52
     * @Description:
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Document(indexName = "search-entity",type = "search", shards = 1, replicas = 0)
    @Setting(settingPath = "/search-setting.json")  //自动创建索引
    @Mapping(mappingPath = "/search-mapping.json")
    public class Search {
    
        /**
         * @Id注解必须是springframework包下的
         */
        @Id
        private String id; //id是model的id拼接模块module
        private String title; //标题
        private String content;// 内容
        private String model; // 对象
        private String module; // 模块
        private String createTime;
    
    }

    添加索引的设置,索引创建,分词,索引映射

    在resource下添加两个文件

    search-mapping.json

    {
      "search": {
        "_all": {
          "enabled": true
        },
        "properties": {
          "id": {
            "type": "text"
          },
          "title": {
            "type": "text",
            "analyzer": "ikSearchAnalyzer",
            "search_analyzer": "ikSearchAnalyzer",
            "fields": {
              "pinyin": {
                "type": "text",
                "analyzer": "pinyinSimpleIndexAnalyzer",
                "search_analyzer": "pinyinSimpleIndexAnalyzer"
              }
            }
          },
          "content": {
            "type": "text",
            "analyzer": "ikSearchAnalyzer",
            "search_analyzer": "ikSearchAnalyzer",
            "fields": {
              "pinyin": {
                "type": "text",
                "analyzer": "pinyinSimpleIndexAnalyzer",
                "search_analyzer": "pinyinSimpleIndexAnalyzer"
              }
            }
          },
          "model": {
            "type": "text"
          },
          "module": {
            "type": "text"
          },
          "createTime": {
            "type": "date",
            "format": "yyyy-MM-dd HH:mm:ss"
          }
        }
      }
    }

    search-setting.json

    {
      "index": {
        "analysis": {
          "filter": {
            "edge_ngram_filter": {
              "type": "edge_ngram",
              "min_gram": 1,
              "max_gram": 50
            },
            "pinyin_simple_filter": {
              "type": "pinyin",
              "first_letter": "prefix",
              "padding_char": " ",
              "limit_first_letter_length": 50,
              "lowercase": true
            }
          },
          "char_filter": {
            "tsconvert": {
              "type": "stconvert",
              "convert_type": "t2s"
            }
          },
          "analyzer": {
            "ikSearchAnalyzer": {
              "type": "custom",
              "tokenizer": "ik_max_word",
              "char_filter": [
                "tsconvert"
              ]
            },
            "pinyinSimpleIndexAnalyzer": {
              "tokenizer": "keyword",
              "filter": [
                "pinyin_simple_filter",
                "edge_ngram_filter",
                "lowercase"
              ]
            }
          }
        }
      }
    }

    添加dao

    package com.zh.search.dao;
    
    import com.zh.search.entity.Search;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    
    /**
     * @Auther: suruozhong
     * @Date: 2019/11/14 16:41
     * @Description:
     */
    public interface SearchRepository extends ElasticsearchRepository<Search,String> {
    }

    代码实例

    package com.zh.search.service.impl;
    
    import com.zh.common.core.kit.DateKit;
    import com.zh.common.core.kit.RandomKit;
    import com.zh.common.core.util.R;
    import com.zh.search.dao.SearchRepository;
    import com.zh.search.entity.Search;
    import com.zh.search.service.SearchService;
    import org.elasticsearch.action.admin.indices.analyze.AnalyzeAction;
    import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
    import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequestBuilder;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.Field;
    import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.Client;
    import org.elasticsearch.common.text.Text;
    import org.elasticsearch.index.query.DisMaxQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.SearchHit;
    import org.elasticsearch.search.SearchHits;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
    import org.springframework.data.elasticsearch.core.SearchResultMapper;
    import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
    import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
    import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
    import org.springframework.data.elasticsearch.core.query.SearchQuery;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    import javax.annotation.Resource;
    import java.util.*;
    
    /**
     * @Auther: suruozhong
     * @Date: 2019/11/14 13:59
     * @Description:
     */
    @Service
    public class SearchServiceImpl implements SearchService {
    
        @Autowired
        private SearchRepository searchRepository;
        @Resource
        private ElasticsearchTemplate elasticsearchTemplate;
    
        /**
         * 添加数据
         * @param title
         */
        @Override
        public void saveM(String title){
            Search model = new Search();
            model.setId(RandomKit.getDateNumber());
            model.setTitle(title);
            model.setContent(title);
            model.setCreateTime(DateKit.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            searchRepository.save(model);
        }
    
        /**
         * 获取所有数据
         * @return
         */
        @Override
        public R getAll(){
            return new R(searchRepository.findAll());
        }
    
        /**
         * 分页分词高亮关键词查询
         * @param keyword
         * @param current
         * @param size
         * @return
         */
        @Override
        public Page page(String keyword,Integer current,Integer size){
            // 页码
            Page<Search> page = null;
            try {
    
                // 构建查询
                NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
    
                // 索引查询
                searchQuery.withIndices("search-entity");
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", keyword).boost(2f);
                boolQueryBuilder.must(queryBuilder);
                //时间范围查询
    //            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
    //                    .from(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss"))
    //                    .to(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss")));
                searchQuery.withQuery(boolQueryBuilder);
    
                // 高亮设置
                List<String> highlightFields = new ArrayList<String>();
                highlightFields.add("title");
                Field[] fields = new Field[highlightFields.size()];
                for (int x = 0; x < highlightFields.size(); x++) {
                    fields[x] = new HighlightBuilder.Field(highlightFields.get(x)).preTags("<high>").postTags("</high>");
                }
                searchQuery.withHighlightFields(fields);
    
                // 分页设置
                searchQuery.withPageable(PageRequest.of(current-1, size));
    
                page = elasticsearchTemplate.queryForPage(searchQuery.build(), Search.class, new SearchResultMapper() {
    
                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
    
                        // 获取高亮搜索数据
                        List<Search> list = new ArrayList<Search>();
                        SearchHits hits = response.getHits();
                        for (SearchHit searchHit : hits) {
                            if (hits.getHits().length <= 0) {
                                return null;
                            }
                            Search model = new Search();
                            // 公共字段
                            model.setId(searchHit.getId());
                            model.setTitle(String.valueOf(searchHit.getSourceAsMap().get("title")));
                            model.setContent(String.valueOf(searchHit.getSourceAsMap().get("content")));
                            Object createTime = searchHit.getSourceAsMap().get("createTime");
    
    
                            //高亮字段
                            if (!StringUtils.isEmpty(searchHit.getHighlightFields().get("title"))) {
                                Text[] text = searchHit.getHighlightFields().get("title").getFragments();
                                model.setTitle(text[0].toString());
                            }
                            list.add(model);
                        }
    
                        if (list.size() > 0) {
                            AggregatedPage<T> result = new AggregatedPageImpl<T>((List<T>) list, pageable,
                                    response.getHits().getTotalHits());
    
                            return result;
                        }
                        return null;
                    }
                });
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return page;
        }
    
        /**
         * 分词查询
         * @param title
         * @return
         */
        @Override
        public List<Search> search(String title) {
            //使用中文拼音混合搜索,取分数最高的,具体评分规则可参照:
            //  https://blog.csdn.net/paditang/article/details/79098830
            SearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(structureQuery(title))
                    .build();
            List<Search> list = searchRepository.search(searchQuery).getContent();
            return list;
        }
    
        /**
         * 高亮关键词查询
         * @param title
         * @return
         */
        @Override
        public List<Search> searchHigh(String title) {
            Client client = elasticsearchTemplate.getClient();
            QueryBuilder query = structureQuery(title);
            // 加入查询中
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.preTags("<high>");//设置前缀
            highlightBuilder.postTags("</high>");//设置后缀
            highlightBuilder.field("title");//设置高亮字段
    //        highlightBuilder.field("title.pinyin");//设置拼音高亮字段
            SearchResponse response = client.prepareSearch("search-entity")
                    .setQuery(query).highlighter(highlightBuilder).execute().actionGet();
    
            // 遍历结果, 获取高亮片段
            SearchHits searchHits = response.getHits();
            Search entity = null;
            List<Search> result = new ArrayList<>();
            for (SearchHit hit : searchHits) {
                Map<String, Object> entityMap = hit.getSourceAsMap();
                entity = new Search();
                if (!StringUtils.isEmpty(hit.getHighlightFields().get("title"))) {
                    Text[] text = hit.getHighlightFields().get("title").getFragments();
                    entity.setTitle(text[0].toString());
                }
    //            if (!StringUtils.isEmpty(hit.getHighlightFields().get("title.pinyin"))) {
    //                Text[] text = hit.getHighlightFields().get("title.pinyin").getFragments();
    //                entity.setTitle(text[0].toString());
    //            }
                result.add(entity);
            }
            return result;
        }
    
        /**
         * 组成搜索条件,中文、拼音混合搜索
         *
         * @param content the content
         * @return dis max query builder
         */
        public DisMaxQueryBuilder structureQuery(String content) {
            //使用dis_max直接取多个query中,分数最高的那一个query的分数即可
            DisMaxQueryBuilder disMaxQueryBuilder = QueryBuilders.disMaxQuery();
            //boost 设置权重,只搜索匹配name
            QueryBuilder ikNameQuery = QueryBuilders.matchQuery("title", content).boost(2f);
    //        QueryBuilder pinyinNameQuery = QueryBuilders.matchQuery("title.pinyin", content);
            disMaxQueryBuilder.add(ikNameQuery);
    //        disMaxQueryBuilder.add(pinyinNameQuery);
            return disMaxQueryBuilder;
        }
    
        /**
         * 获取分词结果
         * @param keyword
         * @param type  type取值,拼音-pinyin,IK-ik_max_word,.....
         * @return
         */
        @Override
        public List analyze(String keyword,String type){
    
            AnalyzeRequest analyzeRequest = new AnalyzeRequest("search-entity")
                    .text(keyword)
                    .analyzer(Optional.ofNullable(type).orElse("ik_max_word"));
            List<AnalyzeResponse.AnalyzeToken> tokens = elasticsearchTemplate.getClient().admin().indices()
                    .analyze(analyzeRequest)
                    .actionGet()
                    .getTokens();
            return tokens;
        }
    
    }
  • 相关阅读:
    网页中防拷贝、屏蔽鼠标右键代码
    Enterprise Library Exception Handling Application Block Part 1
    vs debug 技巧
    Winforms:消除WebBrowser的GDI Objects泄露
    WinForm窗体之间交互的一些方法
    TableLayoutPanel用法
    Winforms:把长ToolTip显示为多行
    Winforms: 不能在Validating时弹出有模式的对话框
    Winforms: 复杂布局改变大小时绘制错误
    读取Excel默认工作表导出XML
  • 原文地址:https://www.cnblogs.com/suruozhong/p/11872233.html
Copyright © 2011-2022 走看看