Join 查詢解析器

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'
  )

join 作業是在詞彙的基礎上完成的,因此 fromto 欄位必須使用相容的欄位類型。例如:在 StrFieldIntPointField 之間進行 join 將無法運作。同樣地,在 StrField 和使用 LowerCaseFilterFactoryTextField 之間進行 join,只適用於字串欄位中已轉換為小寫的值。

參數

此查詢解析器採用以下參數

from

必要

預設值:無

欄位的名稱,其中包含要在 to 欄位中搜尋的值。可以是單值或多值,但必須具有與 to 欄位中表示的欄位相容的欄位類型。

to

必要

預設值:無

欄位的名稱,其值將與在 from 欄位中找到的值進行檢查。可以是單值或多值,但必須具有與 from 欄位相容的欄位類型。

fromIndex

選用

預設值:請參閱說明

執行「from」查詢 (v 參數) 和收集「from」值的索引名稱。必須位於與處理請求的核心相同的節點上。如果未定義此參數,則預設為處理核心的值。請參閱下方的 跨單一分片集合進行 Join跨集合 Join,以取得更多資訊。

score

選用

預設值:請參閱說明

指示 Solr 傳回關於「from」查詢分數的資訊。此參數的值會控制傳回的彙總資訊類型。選項包括 avg (平均值)、max (最大值)、min (最小值)、total (總計) 或 none

如果未指定 method 但已指定 score,則會使用 dvWithScore 方法。如果已指定 method 且不是 dvWithScore,則會忽略 score 值。如需更多詳細資料,請參閱下方的 method 參數文件。

method

選用

預設值:請參閱說明

判斷 Solr 應使用數種查詢實作中的哪一種。選項限制為:indexdvWithScoretopLevelDV

如果未指定,則預設值為 index,除非存在 score 參數,此參數會將其覆寫為 dvWithScore。每種實作都有其各自的效能特性,建議使用者進行實驗以判斷哪種實作最適合其使用案例。下方提供詳細資料和效能啟發法。

index

除非指定了 score 參數,否則預設的 method。它會使用詞彙索引結構來處理請求。效能會隨著「from」欄位中的基數和發佈 (詞彙出現次數) 數量而擴展。當「from」欄位具有低基數、當「to」端傳回大量文件,或當無法容忍偶爾的提交後減速時,請考慮此方法 (這是 index 可避免的其他方法的缺點)。

dvWithScore

返回與結果文件一起的可選「score」統計資訊。如果可以使用 docValues 結構,則會使用它們,但在必要時會回退到欄位快取。首次存取欄位快取會減慢提交後的初始請求,並佔用 JVM 堆上的額外空間,因此在大多數情況下建議使用 docValues。效能會隨著「from」欄位中匹配的值的數量線性擴展。如果需要評分資訊,則必須使用此方法,而且當「from」查詢匹配少數文件時,也應該考慮使用此方法,無論返回的「to」端文件的數量是多少。

dvWithScore 和單值數值

dvWithScore 方法不支援單值數值欄位。建議從 7.0 之前的版本遷移的使用者在遷移期間將欄位類型變更為字串並重建索引。

topLevelDV

僅當 tofrom 欄位具有 docValues 資料時才能使用,且目前不支援數值欄位。它使用頂層 docValues 資料結構來尋找結果。隨著 from 欄位中匹配的值的數量增加,這些資料結構的效能會優於其他方法。但它們的建置成本也很高,並且需要在每次提交後延遲填入,這會在每次提交後第一次使用它們的查詢時導致有時明顯的減速。如果您頻繁提交,並且您的使用案例可以容忍靜態預熱查詢,請考慮將一個查詢新增至 solrconfig.xml,以便此工作作為提交本身的一部分完成,而不是直接附加到使用者請求。當「from」查詢匹配大量文件,且「to」結果集的大小為小到中等時,請考慮使用此方法,但前提是可以容忍偶爾的提交後速度變慢。

跨單分片集合的聯接

您也可以指定 fromIndex 參數,以與另一個核心或單分片集合中的欄位聯接。如果在 SolrCloud 模式下執行,則 fromIndex 參數中指定的集合必須具有單個分片,並且在您要聯接的集合具有副本的所有 Solr 節點上都有一個副本。

讓我們考慮一個範例,您想要使用 Solr 聯接查詢來篩選由獲得奧斯卡獎的導演執導的電影。具體來說,假設我們有兩個具有以下欄位的集合

電影:id、title、director_id、…​

電影導演:id、name、has_oscar、…​

若要使用 Solr 聯接在 movie_directors 集合上篩選由獲得奧斯卡獎的導演執導的電影,您可以將以下篩選查詢傳送至 movies 集合

fq={!join from=id fromIndex=movie_directors to=director_id}has_oscar:true

請注意,篩選器的查詢條件 (has_oscar:true) 是基於使用 fromIndex 指定的集合中的欄位。請記住,您無法使用聯接查詢從 fromIndex 集合傳回欄位,您只能使用這些欄位來篩選「to」集合(電影)中的結果。

接下來,讓我們了解如何在叢集中部署這些集合。假設 movies 集合已部署到四個節點的 SolrCloud 叢集,並具有兩個分片,複製因子為二。具體來說,movies 集合在以下四個節點上具有副本

節點 1:movies_shard1_replica1

節點 2:movies_shard1_replica2

節點 3:movies_shard2_replica1

節點 4:movies_shard2_replica2

若要在 Solr 聯接查詢中將 movie_directors 集合與 movies 集合一起使用,它需要在每個四個節點上都有一個副本。換句話說,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 與聯接

聯接多個分片集合

也可以聯接具有以下條件的集合

  1. 分片數量相同

  2. 兩個集合的 router.name 相同

  3. router.fielduniqueKey 應對應於 tofrom 參數中使用的欄位(請參閱以下詳細資訊和例外情況)

  4. 集合的分片是並置的(請參閱以下範例)

為了簡化,我們使用聯接「from」「多」到「to」「一」的範例。雖然,相同的方法也可以在其他情況下使用。

「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 欄位條件約束

implicit

fromto 匹配 router.field

plaincompositeId

fromto 匹配 uniqueKeyrouter.field

compositeId(預設值)

可以透過 checkRouterField=false 停用條件約束

注意:第三種情況假設索引器會在此情況下指派 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 的連接字串。zkHostsolrUrl 都是可選參數,最多只能指定其中一個。如果未指定 zkHostsolrUrl,則會使用本機 ZooKeeper 叢集。

solrUrl

選用

預設值:無

要查詢的外部 Solr 節點的 URL。必須與 solrconfig.xmlallowSolrUrls 參數中列出的允許清單 URL 的字元完全匹配。如果 URL 不匹配,則此參數將被有效停用。

from

必要

預設值:無

外部集合中的聯接索引鍵欄位名稱。

to

選用

預設值:無

本機集合中的聯接索引鍵欄位名稱。

v

選用

預設值:無

替換為本機參數的查詢。這是將與遠端集合中的文件匹配的查詢字串。

routed

選用

預設值:false

如果為 true,則跨集合聯接查詢將會使用每個分片的雜湊範圍來判斷要為該分片擷取的聯接索引鍵集。此參數可提高跨集合聯接的效能,但它取決於本機集合是否由 to 欄位路由。如果未指定此參數,則跨集合聯接查詢將會嘗試自動判斷正確的值。

ttl

選用

預設值:3600

快取中的跨集合聯接查詢將被視為有效的時間長度(以秒為單位)。跨集合聯接查詢不會知道對遠端集合的變更,因此如果遠端集合已更新,則快取的跨集合查詢可能會產生不準確的結果。在 ttl 期間過期後,跨集合聯接查詢將會針對遠端集合重新執行聯接。

其他參數

任何正常的 Solr 查詢參數也可以指定/作為本機參數傳遞。

跨集合查詢範例

https://127.0.0.1:8983/solr/localCollection/query?fl=id&q={!join method="crossCollection" fromIndex="otherCollection" from="fromField" to="toField" v="*:*"}