概述
空间查询是是利用点,线和多边形等地理信息获得满足特定空间关系的数据,广泛应用于新型农业、零售、服务和安全等领域。本文的业务背景也是基于活动轨迹的多边形查询。
一、空间搜索类型
Solr目前主要支持以下空间搜索类型:
- 索引点或其他形状
- 用边界框或圆形或其他形状过滤搜索结果
- 通过点之间的距离或矩形之间的相对面积来排序或提升得分
- 二维网格上生成热图或者点绘。
本次测试主要是针对多变形的intersect和within查询。
二、配置SOLR并导入测试数据
创建测试collection:geo_test, 步骤如下:
1. 配置schema
拷贝一份默认的schma配置SOLR_INSTALL/server/solr/configsets/_default
到新目录geo_configs
在geo_configs目录下的managed-schema
文件中增加新字段geo
, 并修改location_rpt
的fieldType
<!-- add field geo -->
<field name="geo" type="location_rpt" indexed="true" stored="true" multiValued="true" />
<!-- modify field type to support polygon -->
<fieldType name="location_rpt"
class="solr.SpatialRecursivePrefixTreeFieldType"
spatialContextFactory="org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory"
autoIndex="true"
validationRule="repairBuffer0"
distErrPct="0.025"
maxDistErr="0.001"
distanceUnits="kilometers" />
为了支持doc id的自动生成,需要配置eo_configs目录下的solrconfig.xml
文件。
<updateRequestProcessorChain>
<processor class="solr.UUIDUpdateProcessorFactory"><str name="fieldName">id</str></processor>
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
2.创建schema
此处可以先上传conf到zk上,也可以直接通过solr命令中-d
选项指定配置目录。
cd ${SOLR_HOME}
./server/scripts/cloud-scripts/zkcli.sh \
-zkhost emr-header-1:2181 \
-cmd upconfig \
-confname geo_test \
-confdir ../data/geo_configs/conf
bin/solr create -c geo_test -n geo_test -s 8
3.导入数据
使用curl导入所有的数据
# total 50k documents in this directory
cd geodata
for file in `ls small_data_*`
do
echo "loading data file: $file.."
curl 'http://localhost:8983/solr/geo_test/update/csv?commit=true&separator=%2C&fieldnames=geo,MSOA11NM_s,MSOA11CD_s&header=true' \
-H 'Content-type:text/csv; charset=utf-8' \
--data-binary @$file
((counter++))
done
通过访问http://spark:8983/solr/#/geo_test/query ,查看导入的数据。
四、测试
Solr Cloud环境
- 共4个节点
- 每个节点JVM MEMORY 4G
测试表:geo_test
- 8个shard
- 每个节点2个shard
- 每个doc都的geo字段包含几百个顶点的多边形
- 测试数据分别为10万、100万、2000万
通过Python脚本随机生成不同顶点个数的多边形,对Intersect和within的多边形查询进行测试。
#!/usr/bin/python
import random
import requests
import json
url = "http://localhost:8983/solr"
collection = 'geo_test'
def query(vertices_numbers, pattern, isPolygon = False):
data=[ ]
first_group = ''
for i in range(vertices_numbers - 1):
latitude = random.randint(-4677000, 4643800) / 100000
longitude = random.uniform(-2470650, -2349470) / 100000
group = "{}%20{}".format(latitude, longitude)
data.append(group)
if i == 0:
first_group = group
if vertices_numbers > 1 :
data.append(first_group)
query_data = ''
if isPolygon:
query_data ="POLYGON(({}))".format(",".join(data))
else:
query_data = " ".join(data)
condition = "geo:%22{}({})%22&q=*:*".format(pattern, query_data)
request = "{}/{}/select?fq={}".format(url, collection, condition)
response = requests.get(request)
json_data = json.loads(response.text)
return "query time:{}(ms)".format(json_data['responseHeader']['QTime'])
def polygonIntersectsQuery(vertices_numbers):
return "Polygon have:{} vertices. Polygon intersect {}".format(vertices_numbers, query(vertices_numbers, 'Intersects', True))
def polygonWithIn(vertices_numbers):
return "Polygon have:{} vertices. Polyton within {}".format(vertices_numbers, query(vertices_numbers, 'WithIn', True))
if __name__ == '__main__':
# polygon intersect query
vertices_set = [10, 50, 100, 150, 200, 250]
for v in vertices_set:
print(polygonIntersectsQuery(v))
# polygon within query
for v in vertices_set:
print(polygonWithIn(v))
五、结论
不同数据量、不同顶点多边形intersect的测试结果:
不同数据量、不同顶点多边形within的测试结果:
千万级别内的数据量,200-300个顶点的多边形复杂查询,毫秒级响应是没有问题的
参考
- 在centos7上安装gdal:https://gis.stackexchange.com/questions/263495/how-to-install-gdal-on-centos-7-4
- prj查询:http://prj2epsg.org/search
- gdal下载:http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries
- 地理数据load到solr:http://docs.geoserver.org/latest/en/user/community/solr/load.html
- SOLR7.3: https://lucene.apache.org/solr/guide/7_3/
- Lucene Geo Benchmark: https://home.apache.org/~mikemccand/geobench.html
- epsg: http://www.epsg.org/
- Loading spatial data into SOLR : http://docs.geoserver.org/latest/en/user/community/solr/load.html
- solr自动ID生成: https://solr.pl/en/2013/07/08/automatically-generate-document-identifiers-solr-4-x/