空间搜索
Solr 支持在空间/地理空间搜索中使用位置数据。
使用空间搜索,您可以
-
索引点或其他形状
-
按边界框或圆或其他形状过滤搜索结果
-
按点之间的距离或矩形之间的相对面积对评分进行排序或提升
-
生成用于生成热图或点绘图的 2D 网格化面计数数字。
空间搜索有四种主要字段类型可用
-
LatLonPointSpatialField
-
PointType
-
SpatialRecursivePrefixTreeFieldType
(简称 RPT),包括其派生RptWithGeometrySpatialField
-
BBoxField
LatLonPointSpatialField
是针对纬度经度点数据最常见用例的理想字段类型。RPT 提供了一些更多功能,以满足更高级/自定义用例和多边形和热图等选项。
RptWithGeometrySpatialField
用于索引和搜索非点数据,尽管它也可以处理点。它无法进行排序/提升。
BBoxField
用于索引边界框、按框查询、指定搜索谓词(相交、包含、包含、不相交、相等)以及相关性排序/提升,如重叠率或仅仅是面积。
Solr Wiki 的 空间搜索 部分中提供了本指南中没有的一些深奥细节。
LatLonPointSpatialField
以下是通常如何在架构中配置 LatLonPointSpatialField
(LLPSF)
<fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/>
LLPSF 支持切换 indexed
、stored
、docValues
和 multiValued
。当启用“indexed”(默认值)时,LLPSF 在内部使用 2 维 Lucene“点”(BDK 树)索引。当启用“docValues”时,纬度和经度对将以位交错方式放入 64 位并放入 Lucene DocValues。docValues 数据的精度约为一厘米。
索引点
对于索引大地测量点(纬度和经度),按“lat,lon”顺序(逗号分隔)提供。
对于索引非大地测量点,则取决于具体情况。如果为 RPT,则使用x y
(一个空格)。但是,对于 PointType,则使用x,y
(一个逗号)。
使用查询解析器进行搜索
Solr 有两个用于地理空间搜索的空间“查询解析器”:geofilt
和 bbox
。它们采用以下参数
d
-
必需
默认值:无
径向距离,通常以公里为单位。RPT 和 BBoxField 可以通过设置
distanceUnits
设置其他单位。 pt
-
必需
默认值:无
如果使用纬度和经度,则使用
lat,lon
格式的中心点。否则,对于 PointType 使用“x,y”,对于 RPT 字段类型使用“x y”。 sfield
-
必需
默认值:无
空间索引字段。
score
-
可选
默认值:
none
如果查询用于评分上下文中(例如,作为
q
中的主查询),此 本地参数 确定将生成哪些评分。高级选项;PointType 不支持。有效值是
-
none
:固定评分为1.0
。 -
kilometers
:字段值和指定中心点之间的距离(公里)。 -
miles
:字段值和指定中心点之间的距离(英里)。 -
degrees
:字段值和指定中心点之间的距离(度)。 -
distance
:字段值和指定中心点之间的距离,以为此字段配置的distanceUnits
为单位。 -
recipDistance
:1 / 距离。不要将其用于索引的非点形状(例如,多边形)。结果将是错误的。对于 RPT,仅建议将其用于多值点数据,因为实现的可扩展性不是很好,对于单值字段,您应该改为使用一个单独的非 RPT 字段,纯粹用于距离排序。
当与
BBoxField
一起使用时,支持其他选项 -
overlapRatio
:索引形状和查询形状之间的相对重叠。 -
area
:基于哈弗辛的重叠形状面积,以为此字段配置的distanceUnits
表示 -
area2D
:基于笛卡尔坐标的重叠形状面积,以为此字段配置的distanceUnits
表示
-
filter
-
可选
默认值:
true
如果您只想让查询进行评分(使用上述
score
本地参数),而不是进行筛选,请将此本地参数设置为false
。高级选项;不受 PointType 支持。
geofilt
geofilt
筛选器允许您根据与给定点之间的地理空间距离(又称“大圆距离”)来检索结果。另一种看待方式是,它创建了一个圆形形状筛选器。例如,若要查找给定经纬度点五公里范围内的所有文档,您可以输入
&q=*:*&fq={!geofilt sfield=store}&pt=45.15,-93.85&d=5
此筛选器返回初始点周围给定半径圆圈内的所有结果
bbox
bbox
筛选器与 geofilt
非常相似,但它使用计算出的圆的边界框。请参阅下图中的蓝色框。它采用与 geofilt 相同的参数。
以下是一个示例查询
&q=*:*&fq={!bbox sfield=store}&pt=45.15,-93.85&d=5
矩形形状的计算速度更快,因此当可以返回半径之外的点时,它有时用作 geofilt
的替代方案。但是,如果理想目标是一个圆,但您希望它运行得更快,那么请考虑改用 RPT 字段并尝试一个较大的 distErrPct
值,例如 0.1
(10% 半径)。这将返回半径之外的结果,但它会在形状周围均匀地执行此操作。
当边界框包含极点时,边界框最终会变成一个“边界碗”(一个球冠),如果它接触北极(或如果它接触南极,则接触最高纬度以南的所有值),则它将包含圆的最低纬度以北的所有值。 |
按任意矩形筛选
有时,空间搜索要求需要在矩形区域中查找所有内容,例如用户正在查看的地图所覆盖的区域。对于这种情况,geofilt 和 bbox 无法解决。这有点像一个技巧,但您可以通过将左下角作为范围的开始,将右上角作为范围的结束,来使用 Solr 的范围查询语法来实现此目的。
以下是一个示例
&q=*:*&fq=store:[45,-94 TO 46,-93]
对于 RPT 和 BBoxField,如果您不使用经纬度坐标(geo="false"
),则必须引用点,因为有空格,例如 "x y"
。
优化:缓存或不缓存
最常见的是将空间查询放入“fq”参数中,即筛选器查询。默认情况下,Solr 会将查询缓存到筛选器缓存中。
如果您知道筛选器查询(无论是空间查询还是非空间查询)相当唯一且不太可能获得缓存命中,请指定 cache="false"
作为本地参数,如以下示例所示。唯一能从这种技术中受益的空间类型是那些具有 docValues 的类型,例如 LatLonPointSpatialField 或 BBoxField。
&q=...mykeywords...&fq=...someotherfilters...&fq={!geofilt cache=false}&sfield=store&pt=45.15,-93.85&d=5
距离排序或提升(函数查询)
有四个距离函数查询
有关这些函数查询的更多信息,请参阅函数查询部分。
更多空间搜索示例
以下是您可以在 Solr 中使用空间搜索执行的一些更有用的示例。
用作子查询以扩展搜索结果
此处我们将查询佛罗里达州杰克逊维尔的结果,或查询距离 45.15,-93.85(明尼苏达州布法罗附近) 50 公里范围内的结果
&q=*:*&fq=(state:"FL" AND city:"Jacksonville") OR {!geofilt}&sfield=store&pt=45.15,-93.85&d=50&sort=geodist()+asc
按距离分面
要按距离分面,您可以使用 frange
查询解析器
&q=*:*&sfield=store&pt=45.15,-93.85&facet.query={!frange l=0 u=5}geodist()&facet.query={!frange l=5.001 u=3000}geodist()
还有其他方法也可以做到这一点,例如在每个 facet.query 中使用 {!geofilt}
。
提升最近结果
使用DisMax 查询解析器或扩展 DisMax (eDisMax) 查询解析器,您可以将空间搜索与提升函数结合起来,以提升最近的结果
&q.alt=*:*&fq={!geofilt}&sfield=store&pt=45.15,-93.85&d=50&bf=recip(geodist(),2,200,20)&sort=score desc
RPT
RPT 指的是 SpatialRecursivePrefixTreeFieldType
(又称 RPT)和一个扩展版本:RptWithGeometrySpatialField
(又称带几何的 RPT)。与 LatLonPointSpatialField 相比,RPT 提供了多项功能改进
-
非大地测量 - geo=false 一般 x 和 y(不是纬度和经度)——如果需要
-
除了圆形和矩形之外,还可以通过多边形和其他复杂形状进行查询
-
能够对非点形状(例如多边形)和点进行索引,请参见 RptWithGeometrySpatialField
-
热图网格切面
RPT 与 LatLonPointSpatialField
共享各种功能。这里列出了一些
-
纬度/经度索引点数据;可能有多个值
-
使用
geofilt
、bbox
过滤器和范围查询语法进行快速过滤(支持跨越日期变更线) -
众所周知的文本 (WKT) 形状语法(用于指定多边形和其他复杂形状),以及 GeoJSON。除了索引和搜索之外,它还适用于
wt=geojson
(GeoJSON Solr 响应编写器)和[geo f=myfield]
(geo Solr 文档转换器)。 -
通过
geodist
进行排序/提升——虽然不推荐
虽然 RPT 支持距离排序/提升,但它执行此操作非常低效,因此将来可能会将其删除。幸运的是,您还可以使用 LatLonPointSpatialField 和 RPT。对距离排序/提升使用 LLPSF;它只需要为此具有 docValues;可以禁用索引属性,因为它不会被使用。 |
RPT 的架构配置
要使用 RPT,必须在集合的架构中注册并配置字段类型。此字段类型有很多选项。
name
-
必需
默认值:无
字段类型的名称。
class
-
必需
默认值:无
这应该是
solr.SpatialRecursivePrefixTreeFieldType
。但请注意,Lucene 空间模块包含除 RPT 之外的其他一些所谓的“空间策略”,特别是 TermQueryPT*、BBox、PointVector* 和 SerializedDV。Solr 需要一个相应的字段类型才能使用这些策略。带星号的策略有这些字段类型。 spatialContextFactory
-
可选
默认值:无
这是一个 Java 类名,用于一个内部扩展点,该扩展点控制对形状定义和解析的支持。有两个内置别名用于已知实现:
Geo3D
和JTS
。默认空白值不支持多边形。 geo
-
可选
默认值:
true
如果为
true
,将使用纬度和经度坐标,并且数学模型通常为球体。如果为false
,则坐标将是使用欧几里得/笛卡尔几何的 2D 平面上的通用 X 和 Y。 format
-
可选
默认值:
WKT
定义要使用的形状语法/格式。默认为
WKT
,但GeoJSON
是另一种流行的格式。Spatial4j 控制此功能并支持 其他格式。如果给定形状可以解析为“lat,lon”或“x y”,那么始终支持该形状。 distanceUnits
-
可选
默认值:无
这用于指定整个字段使用过程中所用距离测量单位。可以是
degrees
、kilometers
或miles
。它适用于涉及该字段的几乎所有距离测量:maxDistErr
、distErr
、d
、geodist
,以及当分数为distance
、area
或area2d
时分数。但是,它不影响嵌入在 WKT 字符串中的距离(例如,BUFFER(POINT(200 10),0.2)
),它们仍然以度为单位。如果
geo
为true
,则distanceUnits
的默认值为kilometers
;如果geo
为false
,则默认值为degrees
。distanceUnits
替换了units
属性;该属性现已弃用,并且与此属性互斥。 distErrPct
-
可选
默认值:参见说明
将非点形状(索引和查询)的默认精度定义为
0.0
(完全精确)到0.5
之间的分数。此数字越接近零,形状就越精确。但是,更精确的索引形状会使用更多磁盘空间并且索引时间更长。较大的
distErrPct
值会使查询速度更快,但准确性较低。在查询时,可以在查询语法中覆盖此值,例如覆盖为0.0
以便不近似搜索形状。RPT 字段的默认值为0.025
。对于 RPTWithGeometrySpatialField(见下文),序列化几何体始终完全准确,因此这不会控制准确性,而是控制索引大小的权衡。该字段的 distErrPct
默认值为0.15
。 maxDistErr
-
可选
默认值:参见说明
定义索引数据所需最高详细级别。如果留空,则默认值为一米——略小于 0.000009 度。此设置在内部用于计算适当的 maxLevels(见下文)。
worldBounds
-
可选
默认值:无
定义 x 和 y 的有效数值范围,格式为
ENVELOPE(minX, maxX, maxY, minY)
。如果geo="true"
,则假定为标准的纬度经度世界边界。如果geo=false
,则应定义自己的边界。 distCalculator
-
可选
默认值:参见说明
定义距离计算算法。如果
geo=true
,则haversine
为默认值。如果geo=false
,则cartesian
为默认值。其他可能的值有lawOfCosines
、vincentySphere
和cartesian^2
。 prefixTree
-
可选
默认值:参见说明
定义空间网格实现。由于前缀树(例如 RecursivePrefixTree)将世界映射为网格,因此每个网格单元在下一级分解为另一组网格单元。
如果
geo=true
,则默认前缀树为geohash
,否则为quad
。Geohash 在每个级别有 32 个子节点,quad 有 4 个。Geohash 只能用于geo=true
,因为它严格是地理空间的。第三个选择是
packedQuad
,它通常比quad
更有效,前提是存在许多级别——可能是 20 个或更多。 maxLevels
-
可选
默认值:无
设置索引数据的最大网格深度。相反,通常通过指定
maxDistErr
来计算适当的 maxLevels 更直观。
还有其他: normWrapLongitude
、datelineRule
、validationRule
、autoIndex
、allowMultiOverlap
、precisionModel
。有关更多信息,请参阅下面关于上面引用的 spatialContextFactory
实现的注释,尤其是指向基于 JTS 的链接。
标准形状
RPT 字段类型支持一组标准形状:点、圆(又称缓冲点)、包络(又称矩形或边界框)、线字符串、多边形以及这些形状的“多”变体。包络和线字符串是欧几里得/笛卡尔(平面 2D)形状。底层的 Solr 是实现它们的 Spatial4j 库。要支持其他形状,可以在字段类型上配置 spatialContextFactory
属性以引用其他选项。有两种可用:JTS 和 Geo3D。
JTS 和多边形(平面)
JTS 拓扑套件 是一款流行的计算几何库,采用欧几里得/笛卡尔(平面 2D)模型。它支持多种形状,包括多边形、缓冲形状以及一些无效多边形修复回退。在 Solr 附带的 Spatial4j 的帮助下,多边形支持跨越日期变更线(本初子午线)。您必须下载它(一个 JAR 文件)并将其放置在 Solr 内部的一个特殊位置:SOLR_INSTALL/server/solr-webapp/webapp/WEB-INF/lib/
。您可以在此处轻松下载它:https://mvnrepository.com/artifact/org.locationtech.jts/jts-core/1.15.0。遗憾的是,如果将其放置在其他更典型的 Solr lib 目录中,将不起作用。
将字段类型上的 spatialContextFactory
属性设置为 JTS
。
激活后,将提供其他配置属性;请参阅 org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory 以获取 Javadoc,并记得查看超类的选项。您最有可能启用的一项选项是 autoIndex
(即使用 JTS 的 PreparedGeometry),因为它已被证明可以大幅提升非平凡多边形的性能。
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
spatialContextFactory="JTS"
autoIndex="true"
validationRule="repairBuffer0"
distErrPct="0.025"
maxDistErr="0.001"
distanceUnits="kilometers" />
定义字段类型后,定义一个使用它的字段。
以下是字段“geo”的多边形查询示例,该字段可以是 solr.SpatialRecursivePrefixTreeFieldType 或 RptWithGeometrySpatialField
&q=*:*&fq={!field f=geo}Intersects(POLYGON((-10 30, -40 40, -10 -20, 40 20, 0 0, -10 30)))
搜索谓词后面的括号内是形状定义。该形状的格式由字段类型上的 format
属性控制,默认为 WKT。如果您更喜欢 GeoJSON,则可以指定它。
除了本参考指南和 Spatila4j 的文档之外,还有一些详细信息保留在 Solr Wiki 中,网址为 https://cwiki.apache.org/confluence/display/solr/SolrAdaptersForLuceneSpatial4。
Geo3D 和多边形(椭球体上)
Geo3D 是随 Solr 附带的 Lucene 空间 3D 模块的俗称。它是一个计算几何库,在球体或 WGS84 椭球体上实现各种形状(包括多边形)。Geo3D 特别适用于几何覆盖全球大范围距离或靠近极点的空间应用。Geo3D 之所以如此命名,是因为它使用地心坐标 (X,Y,Z) 的内部实现,而不是它不支持的三维几何。尽管有这些内部细节,您仍然像在 Solr 中通常那样提供纬度和经度。
将字段类型上的 spatialContextFactory
属性设置为 Geo3D
。
<fieldType name="geom"
class="solr.SpatialRecursivePrefixTreeFieldType"
spatialContextFactory="Geo3D"
prefixTree="s2"
planetModel="WGS84"/><!-- or "sphere" -->
定义字段类型后,定义一个使用它的字段。
prefixTree="s2"
设置是可选的,并且仅适用于 Geo3D。它是针对 Geo3D 开发的,比其他网格更有效率。
使用 Geo3D 时,多边形点的顺序很重要!您必须遵循所谓的“右手规则”:外部环必须按逆时针顺序,内部孔必须按顺时针顺序。如果顺序错误,则解释会颠倒,因此多边形将被解释为包含地球的大部分。 |
RptWithGeometrySpatialField
RptWithGeometrySpatialField
字段类型是 SpatialRecursivePrefixTreeFieldType
的派生类型,它还将原始几何体内部存储在 Lucene DocValues 中,用于实现准确搜索。它还可以用于索引点字段。Intersects 谓词(默认)特别快,因为许多搜索结果可以作为准确命中返回,而不需要几何体检查。此字段类型的配置与 RPT 相同,但默认 distErrPct
为 0.15(高于 0.025),因为网格正方形纯粹是为了性能,而不是从根本上表示形状。
可以在 solrconfig.xml
中定义可选的内存中缓存,当数据往往具有许多顶点的形状时应执行此操作。假设您将字段命名为“geom”,则可以通过添加以下内容在 solrconfig.xml
中配置可选缓存——注意缓存名称的后缀
<cache name="perSegSpatialFieldCache_geom"
class="solr.CaffeineCache"
size="256"
initialSize="0"
autowarmCount="100%"
regenerator="solr.NoOpRegenerator"/>
使用此字段类型时,您可能不希望将字段标记为已存储,因为它与 DocValues 数据冗余,并且由于格式(无论是 WKT 还是 GeoJSON)而肯定更大。要从 DocValues 中的搜索结果中检索空间数据,请使用 [geo
转换器。
热图分面
RPT 字段支持为每个网格单元中具有空间数据的文档生成 2D 网格的分面计数。对于高细节网格,这可用于绘制点,对于较低细节,这可用于生成热图。网格单元在索引时根据 RPT 的配置确定。在分面计数时,遍历感兴趣区域中的索引单元,并增加对应于每个单元的计数器网格。Solr 可以以简单的 2D 整数数组或 PNG 的形式返回数据,PNG 对于较大的数据集压缩得更好,但必须解码。
热图功能可通过 Solr 的标准分面功能和 JSON 分面 API 访问。我们现在将继续进行标准分面。作为分面的一部分,它支持 key
本地参数以及排除标记的过滤器查询,就像其他类型分面所做的那样。这允许在同一字段上使用不同的过滤器返回多个热图。
facet
-
可选
默认值:
false
设置为
true
以启用标准分面。 facet.heatmap
-
必需
默认值:无
RPT 类型的字段名称。
facet.heatmap.geom
-
可选
默认值:无
使用矩形范围语法或 WKT 指定要计算热图的区域。它默认为世界。例如:
["-180 -90" TO "180 90"]
。 facet.heatmap.gridLevel
-
可选
默认值:参见说明
特定网格级别,它决定每个网格单元的大小。默认通过
distErrPct
(或distErr
)计算。 facet.heatmap.distErrPct
-
可选
默认值:
0.15
用于计算 gridLevel 的 geom 大小的一部分。它的计算方式与 RPT 的同名参数相同。
facet.heatmap.distErr
-
可选
默认值:无
用于间接选择网格级别的单元格误差距离。它的计算方式与 RPT 的同名参数相同。
facet.heatmap.format
-
可选
默认值:
ints2D
格式,
ints2D
或png
。
您将尝试使用不同的 |
以下是 JSON 中的一些示例输出(为简洁起见插入了“...”)
{gridLevel=6,columns=64,rows=64,minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0,
counts_ints2D=[[0, 0, 2, 1, ....],[1, 1, 3, 2, ...],...]}
输出显示了 gridLevel,这很有趣,因为它通常是从其他参数计算出来的。如果正在开发的界面允许显式增加/减少分辨率的功能,则后续请求可以显式指定 gridLevel。
minX
、maxX
、minY
、maxY
报告了计数所在的区域。这是目标网格级别输入 geom
的最小包围矩形。这可能会环绕日期变更线。columns
和 rows
值是输出矩形被均匀划分的列数和行数。注意:不要均匀地划分屏幕上的投影地图矩形来绘制这些矩形/点,因为如果 geo=true,则单元数据位于十进制度的坐标空间中,或者如果 geo=false,则位于给定的任何单位中。这可以安排成与屏幕上的地图相同,但未必相同。
counts_ints2D
键有一个整数的二维数组。初始外部级别按行顺序(从上到下),然后内部数组是列(从左到右)。如果任何数组都为零,则出于效率原因,将返回一个 null。如果没有匹配的空间数据,则整个值将为 null。
如果 format=png
,则输出键为 counts_png
。它是 4 字节 PNG 的 base-64 编码字符串。PNG 在逻辑上保存与 ints2D 格式完全相同的数据。请注意,alpha 通道字节被翻转,以便于出于诊断目的查看 PNG,因为否则计数必须超过 2^24 才能变为不透明。因此,大于此值的数量将变为不透明。
BBoxField
BBoxField
字段类型为每个文档字段编制一个矩形(边界框)的索引,并支持通过边界框进行搜索。它支持大多数空间搜索谓词,它具有基于搜索矩形和索引矩形之间的重叠或面积的增强相关性模式。它特别适用于其相关性模式。要在模式中配置它,请使用如下配置
<field name="bbox" type="bbox" />
<fieldType name="bbox" class="solr.BBoxField"
geo="true" distanceUnits="kilometers" numberType="pdouble" />
<fieldType name="pdouble" class="solr.DoublePointField" docValues="true"/>
BBoxField 实际上是基于 numberType 引用另一个字段类型的 4 个实例。它还使用一个布尔值来标记日期变更线交叉。假设您想使用相关性功能,则需要 docValues。一些属性与 RPT 字段(如 geo、units、worldBounds 和 spatialContextFactory)相同,因为它们共享一些相同空间基础设施。
要索引一个框,请将一个字段值添加到一个 bbox 字段中,该字段值是 WKT/CQL ENVELOPE 语法中的一个字符串。示例:ENVELOPE(-10, 20, 15, 10)
,即 minX、maxX、maxY、minY 顺序。参数顺序不直观,但这是规范要求的。或者,您可以在 WKT 中提供一个矩形多边形(如果您设置 format="GeoJSON"
,则为 GeoJSON)。
要进行搜索,您可以使用 {!bbox}
查询解析器,或范围语法,例如 [10,-10 TO 15,20]
,或用括号括起来的 ENVELOPE 语法,并带有前导搜索谓词。后者是选择除 Intersects 以外的谓词的唯一方法。例如
&q={!field f=bbox}Contains(ENVELOPE(-10, 20, 15, 10))
现在,要按其中一种相关性模式对结果进行排序,请像这样使用它
&q={!field f=bbox score=overlapRatio}Intersects(ENVELOPE(-10, 20, 15, 10))
score
本地参数可以是 overlapRatio
、area
和 area2D
之一。area
根据文档区域使用球面表面(假设 geo=true
)数学进行评分,而 area2D
使用简单的宽度 * 高度。overlapRatio
根据与文档区域和查询区域相关的重叠量计算 [0-1] 范围内的分数。BBoxOverlapRatioValueSource 的 javadocs 中提供了有关公式的更多信息。还有一个附加参数 queryTargetProportion
,它允许您将公式的查询端加权到公式的索引(目标)端。您还可以使用 &debug=results
来查看有用的分数计算信息。