ES计算一篇文档的单个字段包含多个地理位置,取最小(最大/平均)值

本文档介绍了如何在ES中处理一个文档的地理位置字段包含多个值的情况,通过设置mapping并调整搜索排序模式,实现了根据多个地理位置计算与用户位置的最小距离并排序的功能。文中详细阐述了创建索引、映射、添加文档和搜索排序的过程。
摘要由CSDN通过智能技术生成

背景

项目中遇到如下场景(简化描述):每家公司包含一个或多个实际经营网点,由每个网点承载实际的业务活动。因此公司自身的地理位置没有实际意义,每个网点的地理位置信息,具有实际意义。用户按照条件搜索出符合需要的公司,然后按照地理位置由近及远(相对于用户当前位置)进行排序。

使用ES

鉴于有其他复杂搜索条件,采用ElasticSearch实现项目的搜索要求。ES版本为5.5.0。

基于springboot,用spring-data-elasticsearch建立工程,具体过程不再赘述(参见:https://start.spring.io/)。IDEA自带这个功能,见下图:

初始思路

(1)ES中可以用geo_point类型代表位置信息,参见:geo_point类型说明,因此创建一个document,包含一个类型为GeoPoint的位置信息字段。工程里可以看到GeoPoint类,分别是spring-data-elasticsearch里的org.springframework.data.elasticsearch.core.geo.GeoPoint类和elasticSearch自带的org.elasticsearch.common.geo.GeoPoint类。两者功能类似,都是用经纬度来描述位置的,一个很大的区别在于后者提供了geoHash(由经纬度转化而来的字符串格式,参见:GeoHash原理)到GeoPoint的转化。此处用的spring提供的GeoPoint类。由于我们需要存储多个位置,所以用List<GeoPoint>作为位置的类型。

代码如下:

@Document(indexName = "companyindex", type = "companydata")
@Data
public class Company {

    @Id
    private Long companyId;

    private List<GeoPoint> locations;

    public Company(Long companyId) {
        this.companyId = companyId;
    }
}

此处indexName即为索引名,type为类型名,Company即为文档对象,类中定义的字段即为文档的field,@Id声明companyId为唯一id,添加文档时,即为每个文档的id。

索引文档方法代码如下:

@Service
public class IndexService {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    public void addDoc(Company company) {
        IndexQuery indexQuery = new IndexQuery();
        indexQuery.setObject(company);

        elasticsearchTemplate.index(indexQuery);
    }
}

测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private IndexService indexService;
    @Test
    public void test() {
        Company company1 = new Company(1L);
        List<GeoPoint> locations1 = new ArrayList<>();
        locations1.add(new GeoPoint(10.0000001, 20.0000001));
        locations1.add(new GeoPoint(11.0000001, 21.0000001));
        company1.setLocations(locations1);
        indexService.addDoc(company1);

        Company company2 = new Company(2L);
        List<GeoPoint> locations2 = new ArrayList<>();
        locations2.add(new GeoPoint(20.0000001, 30.0000001));
        locations2.add(new GeoPoint(21.0000001, 31.0000001));
        company2.setLocations(locations2);
        indexService.addDoc(company2);
    }
}

文档添加完成,通过Kibana查询全量数据


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值