空间搜索
Solr 支持用于空间/地理空间搜索的位置数据。
使用空间搜索,您可以
-
索引点或其他形状
-
通过边界框或圆形或其他形状过滤搜索结果
-
按点之间的距离或矩形之间的相对面积对评分进行排序或提升
-
生成用于热图生成或点绘图的 2D 分面计数数字网格。
空间搜索有四种主要字段类型可用
-
LatLonPointSpatialField
(默认启用docValues
) -
PointType
-
SpatialRecursivePrefixTreeFieldType
(简称 RPT),包括RptWithGeometrySpatialField
,一个派生类型 -
BBoxField
LatLonPointSpatialField
是用于纬度-经度点数据的最常见用例的理想字段类型。RPT 为更高级/自定义的用例和多边形和热图等选项提供更多功能。
RptWithGeometrySpatialField
用于索引和搜索非点数据,尽管它也可以处理点数据。它不能进行排序/提升。
BBoxField
用于索引边界框,通过框进行查询,指定搜索谓词(Intersects、Within、Contains、Disjoint、Equals),以及相关性排序/提升,如 overlapRatio 或仅是面积。
有关本指南中未包含的一些深奥细节,可以在 Solr Wiki 的 空间搜索 部分找到。
LatLonPointSpatialField
以下是如何在模式中通常配置 LatLonPointSpatialField
(LLPSF)
<fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/>
LLPSF 支持切换 indexed
、stored
、docValues
和 multiValued
。启用 "indexed" 时(默认),LLPSF 内部使用 2 维 Lucene “Points” (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
: 基于 Haversine 公式计算的重叠形状的面积,以该字段配置的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)。RPT 提供了优于 LatLonPointSpatialField 的几个功能改进
-
非大地测量 – geo=false 通用 x & y(不是纬度和经度)— 如果需要
-
除了圆形和矩形之外,还可以按多边形和其他复杂形状进行查询
-
能够索引非点形状(例如,多边形)以及点 – 请参阅 RptWithGeometrySpatialField
-
热图网格分面
RPT 与 LatLonPointSpatialField
共享各种功能。其中一些在此处列出
-
纬度/经度索引点数据;可能是多值的
-
使用
geofilt
、bbox
过滤器和范围查询语法快速过滤(支持日期线交叉) -
Well-Known-Text (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
和score
,当 score 为distance
、area
或area2d
时。但是,它不影响 WKT 字符串中嵌入的距离(例如,BUFFER(POINT(200 10),0.2)
),这些距离仍以度为单位。如果
geo
为true
,则distanceUnits
默认为kilometers
,如果geo
为false
,则distanceUnits
默认为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
-
可选
默认值:请参见描述
定义空间网格实现。由于 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.17.1。如果将其放置在其他更典型的 Solr lib 目录中,则不幸的是它将无法工作。
将字段类型上的 spatialContextFactory
属性设置为 JTS
。
激活后,可以使用其他配置属性;有关 Javadocs,请参阅 org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory,并记住也要查看超类的选项。您最有可能启用的一项选项是 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 spatial-3d 模块的俗称。它是一个计算几何库,在球体或 WGS84 椭球体上实现各种形状(包括多边形)。Geo3D 特别适合于几何图形覆盖全球大距离或靠近极点的空间应用。Geo3D 之所以如此命名,是因为其内部实现使用地心坐标 (X,Y,Z),而不是用于它不支持的 3 维几何图形。尽管有这些内部细节,您仍然可以像在 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
键具有整数的 2D 数组。初始外部级别按行顺序排列(自上而下),然后内部数组是列(自左向右)。如果任何数组都将为全零,则出于效率原因,将改为返回 null。如果没有匹配的空间数据,则整个值为 null。
如果 format=png
,则输出键为 counts_png
。它是一个 4 字节 PNG 的 base-64 编码字符串。该 PNG 在逻辑上与 ints2D 格式包含完全相同的数据。请注意,为了便于诊断查看 PNG,alpha 通道字节已翻转,否则计数必须超过 2^24 才能变为不透明。因此,大于此值的计数将变为不透明。
BBoxField
BBoxField
字段类型为每个文档字段索引一个矩形(边界框),并支持通过边界框进行搜索。它支持大多数空间搜索谓词,它具有基于搜索矩形和索引矩形之间的重叠或面积的增强相关性模式。它的相关性模式尤其有用。要在 schema 中配置它,请使用如下配置:
<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
来查看有用的分数计算信息。