SpringBoot整合SpringDataElasticSearch7.17.7 通过ElasticsearchRestTemplate 完成地理搜索 矩形搜索,附近人搜索, 距离搜索

1 pom文件,yml 文件设置,就不说了

2 pojo文件

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "scenie", shards = 1, replicas = 1)
public class Scenie {

    @Id
    private Long id;

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

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

    @Field(name = "city", type = FieldType.Keyword)
    private String city;

    @Field(name = "area", type = FieldType.Keyword)
    private String area;

    //****** elasticsearch geo坐标 类型 *****
    @GeoPointField
    private GeoPoint location;

    //日期类型
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Field(name = "createTime", format = DateFormat.custom, type = FieldType.Date, pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

}

3 测试类

import cn.haiwang.es_test_1.pojo.Scenie;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;


@RestController
public class Controller_2 {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 添加
     */
    @RequestMapping("/add")
    public void add() {
        Double lat = 39.948054;
        Double lon = 116.391411;
        GeoPoint geoPoint = new GeoPoint(lat, lon);

        Scenie scenie = new Scenie(1L, "绿地万怡酒店", "沪宜公路3101号", "上海", "嘉定新城", geoPoint, LocalDateTime.now());
        elasticsearchRestTemplate.save(scenie);
    }

    /**
     * geo_bounding_box 矩形过滤 (左上角 一个坐标,右下角一个坐标,画个距形过滤)
     *
     * @return
     */
    @RequestMapping("/find_byBoundingBox")
    public Object find_byBoundingBox(@RequestParam(defaultValue = "0") Integer pageIndex,
                                     @RequestParam(defaultValue = "10") Integer pageSize) {
        //分页信息
        PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);

        //矩形过滤
        GeoBoundingBoxQueryBuilder geoBoundingBoxQueryBuilder = QueryBuilders.geoBoundingBoxQuery("location")
                .setCorners(39.968263, 116.315444,
                        39.870426, 116.464347);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                //查询
                .withQuery(geoBoundingBoxQueryBuilder)
                //分页
                .withPageable(pageRequest);
        SearchHits<Scenie> scenie = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Scenie.class, IndexCoordinates.of("scenie"));
        List<SearchHit<Scenie>> searchHits = scenie.getSearchHits();

        PageImpl<SearchHit<Scenie>> searchHits1 = new PageImpl<>(searchHits, pageRequest, scenie.getTotalHits());
        return searchHits1;
    }

    /**
     * geo_distance 距离查询(圆形过滤),从一个点坐标,指定距离画个画过滤
     *
     * @param pageIndex
     * @param pageSize
     * @param distance  想查看周边几公里的信息
     * @return
     */
    @RequestMapping("/find_byDistance")
    public Object find_byDistance(@RequestParam(defaultValue = "0") Integer pageIndex,
                                  @RequestParam(defaultValue = "10") Integer pageSize,
                                  @RequestParam(defaultValue = "2") Double distance) {

        //分页信息
        PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);

        //假如 查询 这个坐标 ,周边几 km的信息
        Double lat = 39.948054;
        Double lon = 116.391411;

        // 按距离升序
        GeoDistanceSortBuilder distanceSortBuilder = new GeoDistanceSortBuilder("location", lat, lon);
        distanceSortBuilder.order(SortOrder.ASC);
        distanceSortBuilder.unit(DistanceUnit.KILOMETERS);

         以某点为中心,搜索指定范围
        GeoDistanceQueryBuilder distanceQueryBuilder = QueryBuilders.geoDistanceQuery("location")
                .point(lat, lon)
                // 定义查询单位:公里
                .distance(distance, DistanceUnit.KILOMETERS);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //查询
        nativeSearchQueryBuilder.withQuery(distanceQueryBuilder);
        //分页
        nativeSearchQueryBuilder.withPageable(pageRequest);
        //排序
        nativeSearchQueryBuilder.withSort(distanceSortBuilder);

        SearchHits<Scenie> jingqu = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Scenie.class, IndexCoordinates.of("scenie"));
        List<SearchHit<Scenie>> searchHits = jingqu.getSearchHits();

        LinkedHashMap<String, String> hashMap = new LinkedHashMap<>();

        searchHits.stream().forEach(searchHit -> {
            String name = searchHit.getContent().getName();
            //注意:没有指定排序,这里为null
            String px = searchHit.getSortValues().get(0).toString();

            //计算两点间的距离
            double calculate = GeoDistance.ARC.calculate(lat, lon,
                    searchHit.getContent().getLocation().getLat(),
                    searchHit.getContent().getLocation().getLon(), DistanceUnit.KILOMETERS);

            hashMap.put(name, "排序里的距离:" + px + "------距离(算法方法算的):" + calculate);
        });
        return hashMap;
    }

}

附录:elasticsearch 索引创建

PUT scenie
{
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "address": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "area": {
        "type": "keyword"
      },
      "city": {
        "type": "keyword"
      },
      "location": {
        "type": "geo_point"
      },
      "createTime": {
        "type": "date",
        "format": [
          "yyyy-MM-dd HH:mm:ss"
        ]
      },
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          },
          "name_tishi": {
            "type": "completion",
            "analyzer": "pinyin_analyzer",
            "preserve_separators": true,
            "preserve_position_increments": true,
            "max_input_length": 50
          }
        },
        "analyzer": "ik_max_word"
      }
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "pinyin_analyzer": {
            "tokenizer": "my_pinyin"
          }
        },
        "tokenizer": {
          "my_pinyin": {
            "lowercase": "true",
            "keep_original": "true",
            "remove_duplicated_term": "true",
            "keep_separate_first_letter": "false",
            "type": "pinyin",
            "limit_first_letter_length": "16",
            "keep_full_pinyin": "true"
          }
        }
      }
    }
  }
}


 

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值