连接查询解析器
Join 查询解析器允许用户运行查询,以规范文档之间的关系。
Solr 运行用户选择的子查询(v
参数),识别匹配文档在目标字段(from
参数)中具有的所有值,然后返回包含这些值的目标字段(to
参数)的文档。
实际上,这些语义与 SQL 引擎中的“内部查询”非常相似。例如,考虑以下 Solr 查询
/solr/techproducts/select?q={!join from=manu_id_s to=id}title:ipod
此查询为每个制造商返回一个文档,该制造商生产的产品标题中包含“ipod”,在语义上与以下 SQL 查询相同
SELECT *
FROM techproducts
WHERE id IN (
SELECT manu_id_s
FROM techproducts
WHERE title='ipod'
)
连接操作基于术语进行,因此 from
和 to
字段必须使用兼容的字段类型。例如:StrField
和 IntPointField
之间的连接将不起作用。同样,StrField
和使用 LowerCaseFilterFactory
的 TextField
之间的连接仅适用于字符串字段中已经小写的值。
参数
此查询解析器采用以下参数
from
-
必需
默认值:无
包含在
to
字段中查找值的字段的名称。可以是单值或多值,但必须具有与to
字段中表示的字段兼容的字段类型。 to
-
必需
默认值:无
值的字段名称将根据在
from
字段中找到的值进行检查。可以是单值或多值,但必须具有与from
字段兼容的字段类型。 fromIndex
-
可选
默认值:请参见说明
score
-
可选
默认值:请参见说明
指示 Solr 返回有关“from”查询分数的信息。此参数的值控制返回哪种类型的聚合信息。选项包括
avg
(平均值)、max
(最大值)、min
(最小值)、total
(总计)或none
(无)。如果未指定
method
但指定了score
,则使用dvWithScore
方法。如果指定了method
且不是dvWithScore
,则忽略score
值。有关更多详细信息,请参见下文的method
参数文档。 method
-
可选
默认值:请参见说明
确定 Solr 应使用哪几种查询实现。选项仅限于:
index
、dvWithScore
和topLevelDV
。如果未指定,默认值为
index
,除非存在score
参数,它会将其覆盖为dvWithScore
。每个实现都有其自己的性能特征,建议用户尝试确定哪种实现最适合其用例。详细信息和性能启发式方法如下。index
-
默认的
method
,除非指定了score
参数。它使用术语索引结构来处理请求。性能会随着“from”字段中的基数和发布(术语出现)的数量而变化。当“from”字段具有低基数、当“to”端返回大量文档或无法容忍偶发的提交后速度变慢时(这是index
避免的其他方法的缺点),请考虑此方法。 dvWithScore
-
返回结果文档旁边的可选“得分”统计信息。它使用 docValues 结构(如果可用),但在必要时会回退到字段缓存。第一次访问字段缓存会降低提交后的初始请求速度,并占用 JVM 堆上的额外空间,因此在大多数情况下建议使用 docValues。性能会随着“from”字段中匹配的值的数量线性变化。如果需要得分信息,则必须使用此方法,并且还应在“from”查询匹配的文档较少时考虑此方法,无论返回的“to”端文档数量如何。
dvWithScore 和单值数字dvWithScore
方法不支持单值数字字段。建议从 7.0 之前的版本迁移的用户在迁移期间将字段类型更改为字符串并重建索引。 topLevelDV
-
仅当
to
和from
字段具有 docValues 数据时才能使用,并且当前不支持数字字段。它使用顶级 docValues 数据结构来查找结果。随着from
字段中匹配的值的数量增加,这些数据结构的性能优于其他方法。但是,它们构建成本高,并且需要在每次提交后延迟填充,这会导致在每次提交后使用它们的第一个查询时速度有时会明显变慢。如果您频繁提交并且您的用例可以容忍静态预热查询,请考虑在solrconfig.xml
中添加一个查询,以便将此工作作为提交本身的一部分完成,而不是直接附加到用户请求中。当“from”查询匹配大量文档且“to”结果集大小适中时考虑此方法,但仅当可以容忍偶发的提交后速度变慢时才考虑。
跨单分片集合进行连接
您还可以指定 fromIndex
参数以与另一个核心或单分片集合中的字段进行连接。如果在 SolrCloud 模式下运行,则 fromIndex
参数中指定的集合必须具有一个分片和一个副本,该副本位于您要连接到的集合具有副本的所有 Solr 节点上。
我们考虑一个示例,您希望使用 Solr 联接查询按获得奥斯卡奖的导演筛选电影。具体来说,想象一下我们有两个具有以下字段的集合
movies: id、title、director_id、…
movie_directors: id、name、has_oscar、…
要使用对movie_directors集合的 Solr 联接按获得奥斯卡奖的导演筛选电影,您可以向movies集合发送以下筛选查询
fq={!join from=id fromIndex=movie_directors to=director_id}has_oscar:true
请注意,筛选的查询条件 (has_oscar:true
) 基于使用fromIndex
指定的集合中的字段。请记住,您无法使用联接查询从fromIndex
集合返回字段,您只能使用字段筛选“to”集合(电影)中的结果。
接下来,我们了解如何在集群中部署这些集合。想象一下movies集合部署到一个四节点 SolrCloud 集群,并且有两个分片,复制因子为 2。具体来说,movies集合在以下四个节点上有副本
节点 1:movies_shard1_replica1
节点 2:movies_shard1_replica2
节点 3:movies_shard2_replica1
节点 4:movies_shard2_replica2
要在movies集合的 Solr 联接查询中使用movie_directors集合,它需要在四个节点的每个节点上有一个副本。换句话说,movie_directors必须有一个分片和四个复制因子
节点 1:movie_directors_shard1_replica1
节点 2:movie_directors_shard1_replica2
节点 3:movie_directors_shard1_replica3
节点 4:movie_directors_shard1_replica4
在查询时,JoinQParser
将访问movie_directors集合的本地副本以执行联接。如果本地副本不可用或处于活动状态,则查询将失败。此时,应该清楚的是,由于您仅限于一个分片,并且数据必须复制到需要它的所有节点,因此此方法更适用于 from 集合和 to 集合之间存在一对多关系的小型数据集。此外,如果您向“to”集合添加副本,则还需要为“from”集合添加副本。
有关更多信息,Erick Erickson 撰写了一篇关于联接性能的博客文章,标题为 Solr 和联接。
联接多个分片集合
还可以联接具有
-
相同分片数
-
两个集合的
router.name
相同 -
router.field
或uniqueKey
应对应于to
、from
参数中使用的字段(请参阅下面的详细信息和异常) -
集合的分片并置(请参阅下面的示例)
为了简化,我们使用从“多”联接到“一”的示例。不过,在其他情况下也可以使用相同的方法。
“to”集合 | “from”集合 | |
---|---|---|
节点 1 |
products_shard1_replica1 |
skus_shard1_replica2 |
节点 2 |
products_shard1_replica2 |
skus_shard1_replica1 |
节点 3 |
products_shard2_replica1 |
skus_shard2_replica1 |
节点 4 |
products_shard2_replica2 |
skus_shard2_replica2 |
注意 shardN 如何与其来自其他端集合的对应项相对应。使用 AffinityPlacementPlugin.withCollectionShards 对齐集合分片。
以下是集合路由支持的选项
router.name |
字段约束 |
---|---|
|
|
|
|
|
可以通过 |
注意:第三种情况假设索引器在此情况下分配 sku.id=<product.id>!<sku_id>
,compositeId
逻辑将产品的 SKU 放入与产品同名的分片中。此外,您可以关闭 checkRouterField=false
并通过 _route_
伪字段手动放置每个文档。
例如,如果 skus
集合具有 router.field=product_id
,我们可以通过 q={!join to=id from=product_id fromIndex=skus}color:red
查找红色 SKU 的产品。
跨集合联接
跨集合联接过滤器是联接解析器的一种方法,它将针对远程 Solr 集合执行查询,以获取一组联接键,这些键将用作针对本地 Solr 集合的过滤器查询。
跨集合联接查询将创建一个 CrossCollectionQuery
对象。CrossCollectionQuery
将首先查询远程 Solr 集合并获取联接键的流式表达式结果。当联接键流式传输到节点时,将建立本地索引中匹配文档的位集。这避免了在任何给定时间将整组联接键保留在内存中。此位集在成功执行后插入到过滤器缓存中,就像 Solr 过滤器缓存的正常行为一样。
如果本地索引是根据联接键字段分片的,则跨集合联接可以利用称为 哈希范围查询解析器 的辅助查询解析器。哈希范围查询解析器负责仅返回哈希到给定值范围的文档。这允许 CrossCollectionQuery
查询远程 Solr 集合并仅返回与本地 Solr 集合中的特定分片匹配的联接键。这样做的好处是确保随着分片数量的增加,网络流量不会增加,并允许更大程度的可扩展性。
交叉集合联接查询适用于字符串和点类型字段。用于联接键的字段必须是单值的,并且已启用 docValues。
建议按联接键对本地集合进行分片,因为这允许利用上述优化。
交叉集合联接查询通常不应作为 q
参数的一部分使用。它被设计为用于过滤查询 (fq
参数),以确保适当的缓存。
被查询的远程 Solr 集合应具有已启用 docValues 的联接键的单值字段。
远程 Solr 集合没有任何特定分片要求。
solrconfig.xml 中的联接查询解析器定义
交叉集合联接有一些可以在 solrconfig.xml
中指定的配置选项。
routerField
-
可选
默认值:无
如果使用 CompositeID 路由器按联接字段将文档路由到分片,则应在此处的配置中指定该字段名称。这将允许解析器优化生成的 HashRange 查询。
allowSolrUrls
-
可选
默认值:无
如果指定,此字符串数组指定可以传递给
solrUrl
查询参数的白名单 Solr URL。如果没有此配置,则无法使用solrUrl
参数。此限制对于防止攻击者使用 Solr 探索网络是必需的。
<queryParser name="join" class="org.apache.solr.search.JoinQParserPlugin">
<str name="routerField">product_id_s</str>
<arr name="allowSolrUrls">
<str>http://othersolr.example.com:8983/solr</str>
</arr>
</queryParser>
交叉集合联接查询参数
fromIndex
-
必需
默认值:无
要查询以检索联接键值集合的外部 Solr 集合的名称。
zkHost
-
可选
默认值:无
用于连接到 ZooKeeper 的连接字符串。
zkHost
和solrUrl
都是可选参数,并且最多应指定其中一个。如果未指定zkHost
或solrUrl
,则将使用本地 ZooKeeper 集群。 solrUrl
-
可选
默认值:无
要查询的外部 Solr 节点的 URL。必须与
solrconfig.xml
中的allowSolrUrls
参数中列出的白名单 URL 完全匹配。如果 URL 不匹配,则此参数将被有效禁用。 from
-
必需
默认值:无
外部集合中的联接键字段名称。
to
-
可选
默认值:无
本地集合中的联接键字段名称。
v
-
可选
默认值:无
作为本地参数替换的查询。这是将在远程集合中匹配文档的查询字符串。
路由
-
可选
默认:
false
如果为
true
,跨集合联接查询将使用每个分片的哈希范围来确定要为该分片检索的联接键集。此参数可提高跨集合联接的性能,但它取决于通过to
字段路由的本地集合。如果未指定此参数,跨集合联接查询将尝试自动确定正确的值。 ttl
-
可选
默认:
3600
秒跨集合联接查询在缓存中被视为有效的时间长度,以秒为单位。跨集合联接查询不会意识到远程集合的更改,因此,如果远程集合已更新,则缓存的跨集合查询可能会产生不准确的结果。在
ttl
周期到期后,跨集合联接查询将针对远程集合重新执行联接。 - 其他参数
-
任何常规 Solr 查询参数也可以指定/作为本地参数传递。