Elasticsearch地理形状
Elasticsearch geo_shape地理形状
ES地理范围查询第二讲:地理位置信息之geo_shape
ES GEO地理空间查询java版
Elasticsearch geo_point/geo_shape
通常情况,我们使用一个经纬度坐标表示一个店铺的位置、一个用户的位置,经纬度在地图上仅仅表示一个点,有时候需要表示一个区域,例如:停车场、商场、学校等等,这些区域拥有各种各样的形状,包括:圆形、多边形等等。
ES中存储地理形状的数据类型为: geo_shape
geo_shape支持存储的常用形状数据如下:
提示: 在geo_shape中,点作为一种特殊的形状,geo_shape可以存储一个点。
geo_shape支持GeoJson和WKT(Well-Known Text)格式存储空间形状数据。建议使用wkt。详细支持的格式描述如下面图片上描述。

{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "Dinagat Islands"
}
}
POINT (-77.03653 38.897676)
LINESTRING (-77.03653 38.897676,-77.009051 38.889939)
POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))
MULTIPOINT (102.0 2.0, 103.0 2.0)
MULTILINESTRING ((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0),(100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8))
MULTIPOLYGON (((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0, 102.0 2.0)), ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))
GEOMETRYCOLLECTION (POINT (100.0 0.0), LINESTRING (101.0 0.0, 102.0 1.0))
BBOX (100.0, 102.0, 2.0, 0.0)
PUT /example
{
"mappings": {
"properties": {
"location": {
"type": "geo_shape" // 定义location字段类型为geo_shape
}
}
}
}
POST /example/_doc
{
"location" : {
"type" : "point", // 存储的图形类型为:point,表示存储一个坐标点
"coordinates" : [-77.03653, 38.897676] // 坐标点格式: [经度, 纬度]
}
}
POST /example/_doc
{
"location" : "POINT (-77.03653 38.897676)"
}
POST /example/_doc
{
"location": {
"type": "polygon", // 存储的图形类型为: polygon,表示一个多边形
"coordinates": [ // 支持多个多边形
[ // 第一个多边形,多边形由下面的坐标数组组成。
[100, 0], // 第一个坐标点,坐标格式: [经度, 纬度]
[101, 0],
[101, 1],
[100, 1],
[100, 0] // 最后一个坐标点,要跟第一个坐标点相同,这样多边形才能形成闭合
]
]
}
}
POST /example/_doc
{
"location" : "POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))"
}

当索引的字段类型定义为geo_shape之后,我们就可以通过geo_shape实现图形搜索。
下面是geo_shape支持的图形搜索类型:
intersects - 查询的形状与索引的形状有重叠(默认), 即图形有交集则匹配。
disjoint - 查询的形状与索引的形状完全不重叠。
within - 查询的形状包含索引的形状。
GET /example/_search
{
"query":{
"bool": { // 布尔组合查询语句
"must": {
"match_all": {} // 这里设置其他查询条件,直接匹配全部文档
},
"filter": { // 地理信息搜索,通常不参与相关性计算,所以使用filter包裹起来
"geo_shape": { // geo_shape搜索语句
"location": { // 图形数据存储在location字段
"relation": "within" // 设置图形搜索类型,这里设置为包含关系
"shape": { //这个可以理解为其实就是geojson的geometry的值
"type": "polygon", // 设置图形类型,各种图形格式参考geo_shape的数据格式支持的图形类型
"coordinates": [
[
[
104.0396387972344,
30.59613123035072
],
[
104.0393476378968,
30.59549712177650
],
[
104.0396387858758,
30.59638313574942
],
[
104.0396387972344,
30.59613123035072
]
]
]
}
}
}
}
}
}
}
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.8</version>
</dependency>
MultiPolygonBuilder multiPolygonBuilder = new MultiPolygonBuilder();
String shapeField = "";
for (MultiCondition.GeoPolygon geoPolygon : geoPolygons){
List<Coordinate> coordinateList = geoPolygon.geoPoints.stream().map(point -> new Coordinate(point.getLon(),point.getLat())).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
multiPolygonBuilder.polygon(polygonBuilder);
shapeField = geoPolygon.getShapeField();
}
try {
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(shapeField, multiPolygonBuilder.buildGeometry());
queryBuilder.filter(geoShapeQueryBuilder);
} catch (IOException e) {
e.printStackTrace();
}
package cn.com.example.cdgisdatahandle.config;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
import org.elasticsearch.common.geo.builders.PolygonBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ElasticsearchDaoImpl {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private DefConfig defConfig;
public SearchResponse geoShapeQuery(String wkt) {
String indexName = defConfig.getEs_realtimepeople_index_name();
String geoShapeField = defConfig.getEs_realtimepeople_geoshape_field();
String peopleNumField = defConfig.getEs_realtimepeople_peoplenum_field();
SearchResponse response = null;
SearchRequest request = new SearchRequest();
request.indices(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.trackTotalHits(true);
//查询条件
BoolQueryBuilder boolQueryBuilder = buildWktBoolQueryBuilder(geoShapeField, wkt);
boolQueryBuilder.must(QueryBuilders.matchAllQuery());
boolQueryBuilder.must(QueryBuilders.matchQuery("name", "小明"));
//聚合求和
AggregationBuilder agg = AggregationBuilders.sum("aggSum").field(peopleNumField);
try {
searchSourceBuilder.query(boolQueryBuilder).aggregation(agg);
request.source(searchSourceBuilder);
response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return response;
}
/**
* 构建Wkt条件
* 参考文章:https://blog.csdn.net/z69183787/article/details/105563778
*
* @date 2019/9/26
*/
private BoolQueryBuilder buildWktBoolQueryBuilder(String queryField, String wkt) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
WKTReader wktReader = new WKTReader();
try {
Geometry geom = wktReader.read(wkt);
GeoShapeQueryBuilder geoShapeQueryBuilder = null;
if (wkt.startsWith("POLYGON")) {
Polygon polygon = (Polygon) geom;
List<Coordinate> coordinateList = Arrays.stream(polygon.getCoordinates()).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(queryField, polygonBuilder.buildGeometry())
.relation(ShapeRelation.WITHIN);
boolQueryBuilder.filter(geoShapeQueryBuilder);
} else if (wkt.startsWith("MULTIPOLYGON")) {
MultiPolygon multiPolygon = (MultiPolygon) geom;
int num = multiPolygon.getNumGeometries();
MultiPolygonBuilder multiPolygonBuilder = new MultiPolygonBuilder();
for (int i = 0; i < num; i++) {
Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
List<Coordinate> coordinateList = Arrays.stream(polygon.getCoordinates()).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
multiPolygonBuilder.polygon(polygonBuilder);
}
geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(queryField, multiPolygonBuilder.buildGeometry())
.relation(ShapeRelation.WITHIN);
boolQueryBuilder.filter(geoShapeQueryBuilder);
}
} catch (Exception e) {
System.out.println("构建Wkt条件错误" + e.getMessage());
}
return boolQueryBuilder;
}
public static void main(String[] args) {
ElasticsearchDaoImpl elasticsearchDao = new ElasticsearchDaoImpl();
String wkt = "POLYGON((110.20111083984375 25.431803168948832,110.05897521972658 25.32075284544021,110.07476806640624 25.187233664941914,110.643310546875 25.1070518051296,110.62477111816405 25.230721136478365,110.55198669433594 25.446064798199416,110.35491943359375 25.353644304321108,110.21072387695312 25.299647958643703,110.17501831054689 25.312683764022793,110.20111083984375 25.431803168948832))";
string wkt2 = "MULTIPOLYGON (((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0, 102.0 2.0)), ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))";
long startCurrentTimeMillis = System.currentTimeMillis();
elasticsearchDao.geoShapeQuery(wkt);
elasticsearchDao.geoShapeQuery(wkt2);
long endCurrentTimeMillis = System.currentTimeMillis();
System.out.println((endCurrentTimeMillis - startCurrentTimeMillis)/1000 + " s");
}
}
MultiPolygonBuilder 构建两个多边形,外多边形,内多边形,求环形部分相交数据
用一个数组表示 经纬度 坐标点:
[lon,lat]
一组坐标点放到一个数组来表示一个多边形:
[[lon,lat],[lon,lat], ... ]
一个多边形( polygon )形状可以包含多个多边形;第一个表示多边形的外轮廓,后续的多边形表示第一个多边形内部的空洞:
[
[[lon,lat],[lon,lat], ... ], # main polygon
[[lon,lat],[lon,lat], ... ], # hole in main polygon
...
]
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
我有一个Rails应用程序,现在设置了ElasticSearch和Tiregem以在模型上进行搜索,我想知道我应该如何设置我的应用程序以对模型中的某些索引进行模糊字符串匹配。我将我的模型设置为索引标题、描述等内容,但我想对其中一些进行模糊字符串匹配,但我不确定在何处进行此操作。如果您想发表评论,我将在下面包含我的代码!谢谢!在Controller中:defsearch@resource=Resource.search(params[:q],:page=>(params[:page]||1),:per_page=>15,load:true)end在模型中:classResource'Us
在我的应用程序中我有classUserincludeUser::FooendUser::Foo定义在app/models/user/foo.rb现在我正在使用一个定义了自己的Foo类的库。我收到此错误:warning:toplevelconstantFooreferencedbyUser::FooUser仅引用具有完整路径的Foo,User::Foo,而Foo实际上从来没有指的是Foo。这是怎么回事?更新:才想起我之前遇到过同样的问题,在问题1中看到这里:HowdoIrefertoasubmodule's"fullpath"inruby? 最佳答案
考虑Ruby类Foo::Bar。惯例是将“Foo”命名空间作为一个模块,但它也可以很容易地作为一个类:moduleFoo;classBar;end;end对比:classFoo;classBar;end;end在第二种情况下,Bar不是Foo的内部类,它只是在Foo的单例上定义的另一个常量。在这两种情况下,父类(superclass)都是Object并且它们只包含Kernel模块。它们的祖先链是相同的。因此,除了您可以根据其类使用Foo进行的操作(如果是类则实例化,如果是模块则扩展/包含),命名空间的性质是否对有任何影响酒吧?是否有令人信服的理由选择其中一个名称间距而不是另一个?我看到
我在将模块包含在命名空间类中时遇到问题。下面的示例抛出错误uninitializedconstantBar::Foo::Baz(NameError)。我在这里缺少哪些基本的Ruby知识?moduleFoomoduleBazdefhelloputs'hello'endendendmoduleBarclassFooincludeFoo::Bazendendfoo=Bar::Foo.new 最佳答案 使用::强制查找到顶层:moduleBarclassFooinclude::Foo::Bazendend
我想为类定义Fabricator,其命名空间类似于“Foo::Bar”。告诉我它的工作方式。这是我的代码。模型/foo.rbclassFooincludeMongoid::Documentembedded_in:foo_container,polymorphic:truefield:xxx....end模型/foo/bar.rbclassFoo::Bar数据/制造商/foo_bar_fabricator.rbFabricator(:foo_bar,class_name:'Foo::Bar')doyyy'MyString'zzz'MyString'end当我尝试在parino控制台上创建
美团外卖搜索工程团队在Elasticsearch的优化实践中,基于Location-BasedService(LBS)业务场景对Elasticsearch的查询性能进行优化。该优化基于Run-LengthEncoding(RLE)设计了一款高效的倒排索引结构,使检索耗时(TP99)降低了84%。本文从问题分析、技术选型、优化方案等方面进行阐述,并给出最终灰度验证的结论。1.前言最近十年,Elasticsearch已经成为了最受欢迎的开源检索引擎,其作为离线数仓、近线检索、B端检索的经典基建,已沉淀了大量的实践案例及优化总结。然而在高并发、高可用、大数据量的C端场景,目前可参考的资料并不多。因此
开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建