美文网首页JavaSpring Cloud
Elasticsearch7学习笔记(实战)

Elasticsearch7学习笔记(实战)

作者: Vchar_Fred | 来源:发表于2020-10-23 11:48 被阅读0次

    Elasticsearch7学习笔记(上)
    Elasticsearch7学习笔记(中)
    Elasticsearch7学习笔记(下)
    Elasticsearch7学习笔记(实战)

    在SpringBoot中集成Elasticsearch,需要添加如下maven依赖:

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    

    注意在这里引入es的jar包版本要比elasticsearch版本相等或大于(最好相等),否则可能会出现一些奇奇怪怪的问题。

    在application.yml配置文件中添加elasticsearch的配置(可以配置多个)

    spring:
      elasticsearch:
        rest:
          uris: http://192.168.111.55:9200
    

    如果没有什么特殊的配置的话,直接使用springboot自动配置的即可;自定义配置时,可以参考springboot的中配置;

    spring文档:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html

    示例:查询以某个字符开头的数据

    这里我们实现类似12306查询站点时的智能提示功能,即输入北京会智能显示北京开头的站点。下面的示例使用的是webflux

    12306火车站点信息数据拉取

    站点数据:https://www.12306.cn/index/script/core/common/station_name_v10095.js

    数据解析程序如下:

    private static final String STATION_NAME_URL = "https://www.12306.cn/index/script/core/common/station_name_v10095.js";
    
     /**
     * 导入站点数据
     */
    public Mono<String> importTrainStationName() {
        return WebClient.create(STATION_NAME_URL).get().retrieve()
                .onStatus(HttpStatus::is4xxClientError, clientResponse-> Mono.error(new BizException("数据拉取失败")))
                .bodyToMono(String.class)
                .flatMap(body->{
                    List<TrainStationName> list = extractStationName(body);
                    return Mono.just(batchInsert(list));
                });
    }
    
     /**
     * 提取数据
     */
    private List<TrainStationName> extractStationName(String str){
        String[] arr = str.split("\\|");
        List<TrainStationName> list = new ArrayList<>();
        for(int i=1; i<arr.length; i++){
            TrainStationName stationName = new TrainStationName();
            stationName.setCnName(arr[i++]);
            stationName.setCode(arr[i++]);
            stationName.setPinyin(arr[i++]);
            stationName.setPinyinShort(arr[i++]);
            list.add(stationName);
        }
        return list;
    }
    
     /**
     * 导入数据到库中
     */
    private String batchInsert(List<TrainStationName> list){
        int add = 0;
        int totalPull = list.size();
        for(TrainStationName stationName:list){
            LambdaQueryWrapper<TrainStationName> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TrainStationName::getCnName, stationName.getCnName());
            TrainStationName stationNameDb = trainStationNameMapper.selectOne(queryWrapper);
            if(stationNameDb==null){
                add++;
                trainStationNameMapper.insert(stationName);
                stationNameDb = stationName;
            }
    
            if(stationNameDb.getId()!=null){
                boolean exists = trainStationNameRepository.existsById(stationNameDb.getId());
                if(!exists){
                    trainStationNameRepository.save(TrainStationNameDTO.cloneTrainStationName(stationNameDb));
                }
            }
        }
        return String.format("共计拉取:%d条数据,新增:%d条数据", totalPull, add);
    }
    

    站点数据pojo

    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Data;
    
    import java.io.Serializable;
    
    @Data
    @TableName("train_station_name")
    public class TrainStationName implements Serializable {
    
        @TableId(value = "id", type = IdType.AUTO)
        private Long id;
    
        /**
         * 三字码
         */
        @TableField("code")
        private String code;
    
        /**
         * 拼音
         */
        @TableField("pinyin")
        private String pinyin;
    
        /**
         * 拼音简写
         */
        @TableField("pinyin_short")
        private String pinyinShort;
    
        /**
         * 中文名称
         */
        @TableField("cn_name")
        private String cnName;
    
    }
    

    es中的实体类映射

    import lombok.Data;
    import org.springframework.beans.BeanUtils;
    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 top.vchar.train.entity.TrainStationName;
    
    import java.io.Serializable;
    
    @Data
    @Document(indexName = "train_station_name")
    public class TrainStationNameDTO implements Serializable {
    
        @Id
        private Long id;
    
        /**
         * 三字码
         */
        @Field(type = FieldType.Keyword)
        private String code;
    
        /**
         * 拼音
         */
        @Field(type = FieldType.Keyword)
        private String pinyin;
    
        /**
         * 拼音简写
         */
        @Field(type = FieldType.Keyword)
        private String pinyinShort;
    
        /**
         * 中文名称
         */
        @Field(type = FieldType.Keyword)
        private String cnName;
    
        public static TrainStationNameDTO cloneTrainStationName(TrainStationName stationName){
            TrainStationNameDTO dto = new TrainStationNameDTO();
            BeanUtils.copyProperties(stationName, dto);
            return dto;
        }
    }
    

    es的查询语句

    在不晓得如何在代码中拼写语句时,可以先使用es的查询语句试哈。之后再敲代码会清晰许多。

    GET /train_station_name/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "prefix": {
                "cnName.keyword": {
                  "value": "beib"
                }
              }
            },
            {
              "match_phrase_prefix": {
                "pinyin": "beib"
              }
            }
          ]
        }
      }
    }
    

    Java代码实现

    spring封装的ElasticsearchRestTemplate实现,没有特殊查询时建议直接用spring封装的工具类

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
    public Flux<TrainStationNameDTO> findTrainStationName(String keywords) {
    
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        QueryBuilder cnNameQuery = new PrefixQueryBuilder("cnName.keyword", keywords);
        boolQuery.should(cnNameQuery);
        QueryBuilder pinyinQuery = new MatchPhrasePrefixQueryBuilder("pinyin", keywords);
        boolQuery.should(pinyinQuery);
        Query query = new NativeSearchQuery(boolQuery);
        return Flux.fromIterable(elasticsearchRestTemplate.search(query, TrainStationNameDTO.class)).map(SearchHit::getContent);
    }
    

    spring封装的orm框架,做简单的crud操作时强烈建议就用这种方式。类似mybatis

    @Component
    @Document(indexName = "train_station_name")
    public interface TrainStationNameRepository extends ElasticsearchRepository<TrainStationNameDTO, Long> {
    
        /**
         * 查询以keywords开头的站点信息
         * @param cnName 中文
         * @param pinyin 拼音
         * @return 返回结果
         */
        List<TrainStationNameDTO> findByCnNameStartingWithOrPinyinStartingWith(String cnName, String pinyin);
    
    }
    

    最开始的RestHighLevelClient实现

    @Autowired
    private RestHighLevelClient client;
    
    private void useClient(String keywords) {
        SearchRequest request = new SearchRequest("train_station_name");
        request.source(SearchSourceBuilder.searchSource()
                .query(QueryBuilders.boolQuery()
                        .should(QueryBuilders.prefixQuery("cnName.keyword", keywords))
                        .should(QueryBuilders.matchPhrasePrefixQuery("pinyin", keywords))
                )
        );
        try {
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            log.info(JSONObject.toJSONString(search.getHits()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    相关文章

      网友评论

        本文标题:Elasticsearch7学习笔记(实战)

        本文链接:https://www.haomeiwen.com/subject/vncvmktx.html