JSON 查詢 DSL
JSON 請求中提供的查詢和篩選器可以使用功能強大的查詢 DSL 來指定。
查詢 DSL 結構
JSON 請求 API 接受三種不同格式的查詢值
-
使用預設
deftype
(在大多數情況下為lucene
)的有效查詢字串,例如,title:solr
。 -
明確指定其
deftype
的有效本機參數查詢字串,例如,{!dismax qf=title}solr
。 -
具有查詢剖析器名稱和任何相關參數的有效 JSON 物件,例如,
{ "lucene": {"df":"title", "query":"solr"}}
。-
最上層的「查詢」JSON 區塊通常只有一個屬性,表示要使用的查詢剖析器名稱。查詢剖析器屬性的值是一個子區塊,其中包含任何相關參數作為 JSON 屬性。整個結構類似於「本機參數」查詢字串。查詢本身(通常在使用名稱
v
的本機參數中表示)使用鍵query
指定。
-
所有這些語法都可以用於為 JSON 請求 API 的 query
或 filter
屬性指定查詢。
查詢 DSL 範例
以下範例示範如何使用上述討論的每種語法來表示查詢。每個程式碼片段都代表相同的基本搜尋:在名為 name
的欄位中搜尋詞彙 iPod
使用標準查詢 API,使用簡單的查詢字串
-
curl
-
SolrJ
curl -X GET "https://127.0.0.1:8983/solr/techproducts/query?q=name:iPod"
final SolrQuery query = new SolrQuery("name:iPod");
final QueryResponse response = solrClient.query(COLLECTION_NAME, query);
使用 JSON 請求 API,使用簡單的查詢字串
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query" : "name:iPod"
}'
final JsonQueryRequest query = new JsonQueryRequest().setQuery("name:iPod");
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
使用 JSON 請求 API,使用本機參數字串
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "{!lucene df=name v=iPod}"
}'
final JsonQueryRequest query = new JsonQueryRequest().setQuery("{!lucene df=name}iPod");
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
使用 JSON 請求 API,使用完全展開的 JSON 物件
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": {
"lucene": {
"df": "name",
"query": "iPod"
}
}
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> luceneQueryProperties = new HashMap<>();
queryTopLevel.put("lucene", luceneQueryProperties);
luceneQueryProperties.put("df", "name");
luceneQueryProperties.put("query", "iPod");
final JsonQueryRequest query = new JsonQueryRequest().setQuery(queryTopLevel);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
巢狀查詢
Solr 的許多查詢解析器允許查詢彼此巢狀。當使用這些解析器時,使用標準查詢 API 的請求很快就會變得難以撰寫、閱讀和理解。這類查詢通常在 JSON 請求 API 中更容易處理。
巢狀增強查詢範例
舉例來說,請考慮以下三個請求,它們將一個簡單查詢(欄位 name
中的詞語 iPod
)包在一個增強查詢中
使用標準查詢 API
-
curl
-
SolrJ
curl -X GET "https://127.0.0.1:8983/solr/techproducts/query?q={!boost b=log(popularity) v=\'{!lucene df=name}iPod\'}"
final SolrQuery query =
new SolrQuery("{!boost b=log(popularity) v=\'{!lucene df=name}iPod\'}");
final QueryResponse response = solrClient.query(COLLECTION_NAME, query);
使用 JSON 請求 API,混合使用完全展開和本地參數查詢。如您所見,特殊鍵 v
會被替換為鍵 query
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query" : {
"boost": {
"query": {!lucene df=name}iPod,
"b": "log(popularity)"
}
}
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> boostQuery = new HashMap<>();
queryTopLevel.put("boost", boostQuery);
boostQuery.put("b", "log(popularity)");
boostQuery.put("query", "{!lucene df=name}iPod");
final JsonQueryRequest query = new JsonQueryRequest().setQuery(queryTopLevel);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
使用 JSON 請求 API,所有查詢都完全展開為 JSON
+
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": {
"boost": {
"query": {
"lucene": {
"df": "name",
"query": "iPod"
}
},
"b": "log(popularity)"
}
}
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> boostProperties = new HashMap<>();
final Map<String, Object> luceneTopLevel = new HashMap<>();
final Map<String, Object> luceneProperties = new HashMap<>();
queryTopLevel.put("boost", boostProperties);
boostProperties.put("b", "log(popularity)");
boostProperties.put("query", luceneTopLevel);
luceneTopLevel.put("lucene", luceneProperties);
luceneProperties.put("df", "name");
luceneProperties.put("query", "iPod");
final JsonQueryRequest query = new JsonQueryRequest().setQuery(queryTopLevel);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
巢狀布林查詢範例
當使用 BoolQParser 以偽布林邏輯組合多個查詢子句時,查詢巢狀結構是很常見的。
下面的範例顯示如何使用 BoolQParser
建立強大的巢狀查詢。在這個範例中,使用者搜尋 name
欄位中包含 iPod
,且不在 popularity
排名後半部的結果。
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": {
"bool": {
"must": [
{"lucene": {"df": "name", query: "iPod"}}
],
"must_not": [
{"frange": {"l": "0", "u": "5", "query": "popularity"}}
]
}
}
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> boolProperties = new HashMap<>();
final List<Object> mustClauses = new ArrayList<>();
final List<Object> mustNotClauses = new ArrayList<>();
final Map<String, Object> frangeTopLevel = new HashMap<>();
final Map<String, Object> frangeProperties = new HashMap<>();
queryTopLevel.put("bool", boolProperties);
boolProperties.put("must", mustClauses);
mustClauses.add("name:iPod");
boolProperties.put("must_not", mustNotClauses);
frangeTopLevel.put("frange", frangeProperties);
frangeProperties.put("l", 0);
frangeProperties.put("u", 5);
frangeProperties.put("query", "popularity");
mustNotClauses.add(frangeTopLevel);
final JsonQueryRequest query = new JsonQueryRequest().setQuery(queryTopLevel);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
如果 lucene
是預設的查詢解析器,則上述範例可以簡化為
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": {
"bool": {
"must": [
"name:iPod"
],
"must_not": "{!frange l=0 u=5}popularity"
}
}
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> boolProperties = new HashMap<>();
queryTopLevel.put("bool", boolProperties);
boolProperties.put("must", "name:iPod");
boolProperties.put("must_not", "{!frange l=0 u=5}popularity");
final JsonQueryRequest query = new JsonQueryRequest().setQuery(queryTopLevel);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"queries": {
"query_filters":[ // 1.
{"#size_tag":{"field":{"f":"size","query":"XL"}}},
{"#color_tag":{"field":{"f":"color","query":"Red"}}} // 2.
]
},
"query": {
"bool": {
"must": {"param":"query_filters"}, // refer both of 1.
"excludeTags": "color_tag" // excluding 2.
}
}
}'
因此,上面的查詢將只返回符合 size:XL
的文件。
篩選查詢
除了主要查詢本身之外,上面討論的語法也可以用來指定查詢篩選器(在 filter
鍵下)。
例如,上述查詢可以使用篩選子句重寫為
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": {
"bool": {
"must_not": "{!frange l=0 u=5}popularity"
}
},
"filter: [
"name:iPod"
]
}'
final Map<String, Object> queryTopLevel = new HashMap<>();
final Map<String, Object> boolProperties = new HashMap<>();
queryTopLevel.put("bool", boolProperties);
boolProperties.put("must_not", "{!frange l=0 u=5}popularity");
final JsonQueryRequest query =
new JsonQueryRequest().setQuery(queryTopLevel).withFilter("name:iPod");
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
額外查詢
可以在 queries
鍵下指定多個額外查詢,使用上述相同的語法替代方案。每個條目都可以在陣列中有多個值。
要參考這些查詢,請使用 {"param":"query_name"}
,或舊式參考 "{!v=$query_name}"
。請注意這些參考的元數。
根據上下文,參考可能會解析為陣列中的第一個元素,忽略後面的元素,例如,如果將下面的參考從 {"param":"electronic"}
變更為 {"param":"manufacturers"}
,則相當於查詢 manu:apple
,忽略後面的查詢。這些查詢在明確參考之前不會影響查詢結果。
curl -X POST https://127.0.0.1:8983/solr/techproducts/query -d '
{
"queries": {
"electronic": {"field": {"f":"cat", "query":"electronics"}},
"manufacturers": [
"manu:apple",
{"field": {"f":"manu", "query":"belkin"}}
]
},
"query":{"param":"electronic"}
}'
在 JSON 查詢 DSL 中標記
查詢和篩選器會透過將它們包圍在周圍的 JSON 物件中來標記。標籤的名稱指定為 JSON 鍵,查詢字串(或物件)成為與該鍵相關聯的值。標籤名稱屬性會加上雜湊符號為前綴,並且可以包含多個以逗號分隔的標籤。例如:{"#title,tag2,tag3":"title:solr"}
。請注意,與使用寬鬆 JSON 解析規則的其餘 JSON 請求 API 不同,標籤必須以雙引號括起來,因為它們的前面有 #
字元。下面的範例會建立兩個已標記的子句:titleTag
和 inStockTag
。
-
curl
-
SolrJ
curl -X POST https://127.0.0.1:8983/solr/techproducts/select -d '
{
"query": "*:*",
"filter": [
{
"#titleTag": "name:Solr"
},
{
"#inStockTag": "inStock:true"
}
]
}'
final Map<String, Object> titleTaggedQuery = new HashMap<>();
titleTaggedQuery.put("#titleTag", "name:Solr");
final Map<String, Object> inStockTaggedQuery = new HashMap<>();
inStockTaggedQuery.put("#inStockTag", "inStock:true");
final JsonQueryRequest query =
new JsonQueryRequest()
.setQuery("*:*")
.withFilter(titleTaggedQuery)
.withFilter(inStockTaggedQuery);
final QueryResponse response = query.process(solrClient, COLLECTION_NAME);
請注意,上述範例中建立的標籤對搜尋的執行方式沒有任何影響。除非請求的其他部分參考它們,否則標籤不會影響查詢。
分面巢狀文件
本段將許多功能綁在一起。基本上,這是一個在子文件欄位上計數分面時,針對巢狀文件的篩選排除範例,但分面計數會在父文件計數中匯總。您可能需要執行此操作的典型情境是,您要顯示具有各種顏色/尺寸選項的 SKU 的產品(父項)的篩選器。讓我們逐項說明
{
"queries": {
"parents":"content_type:parentDocument", (1)
"sku_fqs": [{"#sku_attr1_tag":"sku_attr1:foo"}, (2)
{"#sku_attr2_tag":"sku_attr2:bar"}
]
},
"filter": {
"#sku_filters":{ (3)
"parent": {
"which": {"param":"parents"},
"filters": {"param":"sku_fqs"}
}}
},
"facet": {
"sku_attr1": { (4)
"type":"terms",
"field":"sku_attr1",
"limit":-1,
"domain": { (5)
"excludeTags":"sku_filters",
"blockChildren":"{!v=$parents}",
"filter":
"{!bool filter=$sku_fqs excludeTags=sku_attr1_tag}"
},
"facet": {
"by_parent":"uniqueBlock({!v=$parents})" (6)
}
}
}
}
1 | 透過額外查詢定義父項篩選器,以供稍後使用。 |
2 | 在不同的 #tags 下宣告兩個 SKU 篩選器,如在 JSON 查詢 DSL 中標記中所述。 |
3 | 定義標籤區塊聯結查詢以供稍後排除。這會將 SKU 聯結到頂層文件,並參考先前定義的 parents 查詢和 SKU 篩選查詢。 |
4 | 計算 SKU 文件上的橫向鑽取 terms 分面。SKU 欄位定義為 sku_attr1 ,我們已設定 limit=-1 ,以便我們取得所有分面值。 |
5 | 使用 excludeTags 移除 domain 中的頂層父項篩選器。blockChildren 值會參考所有父項查詢。然後,我們定義一個篩選器,以限制為 SKU 文件,但排除一個標籤,僅保留 sku_attr2:bar 。 |
6 | 在父文件中計算子分面。另請參閱 uniqueBlock() 和區塊聯結計數。 |