spring-boot整合elasticsearch,以及常用功能 中文分词高亮,按照地理位置排序

  1. 引入pom
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  </dependency>
  1. application.yml 添加es的相关配置
spring:
  data:
    elasticsearch:
      cluster-nodes: localhost:9300
      cluster-name: es_cluster
  1. 创建实体类,
    • 中文分词,需要设置@Document里面的 type = "article",在对应的字段上添加@Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text)注解
    • 根据地理位置排序,需要添加@GeoPointField注解GeoPoint类型的对象
@Data
@Document(indexName = "address", type = "article")
public class Address implements Serializable {
    @Id
    private String id;

    @Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text)
    private String location;

    @GeoPointField
    private GeoPoint geoPoint;

    private String geo;

    public GeoPoint getGeoPoint(){
        String[] split = geo.split(",");
        return new GeoPoint(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
    }
}

  1. elasticsearch常用的一些操作
    @Test
    public void save() {
        Address address = new Address();
        address.setId(UUID.randomUUID().toString());
        address.setLocation("昆山市前进西路1801号");
        address.setGeo("31.386311,120.916435");
        addressDocumentRepository.save(address);
    }
    /**
     * 批量保存数据
     */
    @Test
    public void saveAll() throws IOException {
        File geo = ResourceUtils.getFile("classpath:geo.json");
        String content = new String(Files.readAllBytes(geo.toPath()));
        List<Address> list = JSONUtil.toList(JSONUtil.parseArray(content), Address.class);
        addressDocumentRepository.saveAll(list);
    }
    /**
     * 获取所有数据
     */
    @Test
    public void findAll() {
        Iterable<Address> all = addressDocumentRepository.findAll();
        for (Address address : all) {
            System.out.println(JSONUtil.toJsonStr(address));
        }
    }
    /**
     * 分页查询
     */
    @Test
    public void page() {
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        qb.must(QueryBuilders.termQuery("location", "周庄"));
        Pageable pageable = PageRequest.of(0, 5);
        Page<Address> search = addressDocumentRepository.search(qb, pageable);
        System.out.println("==" + search.getTotalElements());
        System.out.println("==" + search.getTotalPages());
        search.getContent().forEach(address -> System.out.println(JSONUtil.toJsonStr(address)));
    }
    @Test
    public void ikSearch() {
        String searchField = "location";
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.multiMatchQuery("昆山", searchField).analyzer("ik_max_word")
                        .operator(Operator.OR));

        int pageNo = 1;
        int pageSize = 10;

        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(searchField);

        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch("address")
                .setQuery(matchQuery)
                .highlighter(highlightBuilder)
                .setFrom((pageNo - 1) * pageSize)
                // 设置一次返回的文档数量,最大值:10000
                .setSize(pageNo * pageSize)
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();

        List<Address> hitList = getHitList(hits);

        System.out.println(hits.getTotalHits());
        hitList.forEach(address -> {
            System.out.println(JSONUtil.toJsonStr(address));
        });
    }

    /**
     * 构造高亮器
     */
    private HighlightBuilder createHighlightBuilder(String... fieldNames) {
        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // .field("productName")
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        // 设置高亮字段
        for (String fieldName : fieldNames) {
            highlightBuilder.field(fieldName);
        }

        return highlightBuilder;
    }


    /**
     * 处理高亮结果
     */
    private List<Address> getHitList(SearchHits hits) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map;
        for (SearchHit searchHit : hits) {
            // 处理源数据
            map = new HashMap<>(searchHit.getSourceAsMap());
            // 处理高亮数据
            Map<String, Object> hitMap = new HashMap<>();
            searchHit.getHighlightFields().forEach((k, v) -> {
                StringBuilder high = new StringBuilder();
                for (Text text : v.getFragments()) {
                    high.append(text.string());
                }
                hitMap.put(v.getName(), high.toString());
            });
            map.putAll(hitMap);
            list.add(map);
        }
        return JSON.parseArray(JSON.toJSONString(list), Address.class);
    }

    /**
     * 按照位置远近搜索
     */
    @Test
    public void sortByLocation() {
        Pageable pageable = PageRequest.of(0, 20);
        //搜索字段为 location
        GeoDistanceQueryBuilder geoBuilder = new GeoDistanceQueryBuilder("geoPoint");
        geoBuilder.point(31.186245, 121.037991);//指定从哪个位置搜索
        geoBuilder.distance(100, DistanceUnit.KILOMETERS);//指定搜索多少km

        //距离排序
        GeoDistanceSortBuilder sortBuilder = new GeoDistanceSortBuilder("geoPoint", 31.186245, 121.037991);
        sortBuilder.order(SortOrder.ASC);//升序
        sortBuilder.unit(DistanceUnit.METERS);

        //构造查询器
        NativeSearchQueryBuilder qb = new NativeSearchQueryBuilder()
                .withPageable(pageable)
                .withFilter(geoBuilder)
                .withSort(sortBuilder);

        //可添加其他查询条件
        //qb.must(QueryBuilders.matchQuery("address", address));
        Page<Address> page = addressDocumentRepository.search(qb.build());
        List<Address> list = page.getContent();
        list.forEach(l -> {
            double calculate = GeoDistance.PLANE.calculate(l.getGeoPoint().getLat(), l.getGeoPoint().getLon(), 31.186245, 121.037991, DistanceUnit.METERS);
            System.out.println(JSONUtil.toJsonStr(l));
            System.out.println("距离" + (int) calculate + "m");
        });

    }

    @Test
    public void delIndex() {
        elasticsearchTemplate.deleteIndex("address");
    }

    @Test
    public void deleteAll() {
        addressDocumentRepository.deleteAll();
    }

    /**
     * 通过ClassLoader获取resources下文件
     */
    @Test
    public void test2() throws IOException {
        String fileName = "geo.json";
        ClassLoader classLoader = EsTest.class.getClassLoader();
        File file = new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
        String content = new String(Files.readAllBytes(file.toPath()));
        System.out.println(content);
    }


    /**
     * 通过ResourceUtils获取resources下文件
     */
    @Test
    public void test1() throws IOException {
        File geo = ResourceUtils.getFile("classpath:geo.json");
        String content = new String(Files.readAllBytes(geo.toPath()));
        System.out.println(content);
    }
  1. 问题总结
    在多模块情况下,会扫描不到bean,需要添加一个注解
@EnableElasticsearchRepositories(basePackages = "com.good.xxx.xxx")

文章用到的项目源码地址

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值