本文是延續(xù) Solr的使用 系列,前一篇文章已經講了 Solr 的部署和數(shù)據(jù)推送,這里主要以示例方式講述 Solr 的常見查詢語法,同時介紹如何使用 PHP 語言的客戶端 solarium 同 Solr 集群進行數(shù)據(jù)交互。
想要詳細地了解 Solr 查詢語法,可參考 官方wiki。
數(shù)據(jù)格式
用于示例的數(shù)據(jù),我已經推送到了 Solr ,見這里。數(shù)據(jù) Core 為 rooms,數(shù)據(jù)格式形如:
[{
"resblockId": 1111027377528,
"resblockName": "金隅麗港城",
"houseId": 1087599828743,
"cityCode": 110000,
"size": 10.5,
"bizcircleCode": [ 18335711 ],
"bizcircleName": [ "望京" ],
"price": 2300,
"location": "39.997106,116.469306",
"id": "0119df79-68d9-4cd9-ba07-4d6395a4841c"
},
{
"resblockId": 1111047349969,
"resblockName": "融澤嘉園",
... ...
}]
查詢語句的組成
通過向 Solr 集群 GET 請求/solr/core-name/select?query形式的查詢 API 完成查詢,其中 core-name 為查詢的 Core 名稱。查詢語句 query 由以下基本元素項組成,按使用頻率先后排序:
| 名稱 | 描述 | 示例 |
|---|---|---|
| wt | 響應結果的格式 | json |
| fl | 指定結果集的字段 | *(所有字段) |
| fq | 過濾查詢 | id : 0119df79-68d9-4cd9-ba07 |
| start | 指定結果集起始返回的行數(shù),默認 0 | 0 |
| rows | 指定結果集返回的行數(shù),默認 10 | 15 |
| sort | 結果集的排序規(guī)則 | price+asc |
| defType | 設置查詢解析器名稱 | dismax |
| timeAllowed | 查詢超時時間 |
wt
wt 設置結果集格式,支持 json、xml、csv、php、ruby、pthyon,序列化的結果集,常使用 json 格式。
fl
fl 指定返回的字段,多指使用“空格”和“,”號分割,但只支持設置了stored=true的字段。*表示返回全部字段,一般情況不需要返回文檔的全部字段。
字段別名:使用displayName:fieldName形式指定字段的別名,例如:
fl=id,sales_price:price,name
函數(shù):fl 還支持使用 Solr 內置函數(shù),例如根據(jù)單價算總價:
fl=id,total:product(size,price)
fq
fq 過濾查詢條件,可充分利用 cache,所以可以利用 fq 提高檢索性能。
sort
sort 指定結果集的排序規(guī)則,格式為<fieldName>+<sort>,支持 asc 和 desc 兩種排序規(guī)則。例如按照價格倒序排列:
sort=price+desc
也可以多字段排序,價格和面積排序:
sort=price+asc,size+desc
條件查詢
查詢字符串 q 由以下元素項組成,字段條件形如fieldName:value格式:
| 名稱 | 描述 | 示例 |
|---|---|---|
| q | 查詢字符串 | : |
| q.op | 表達式之間的關系操作符 | AND/OR |
| df | 查詢被索引的字段 | id:0119df79-68d9-4cd9-ba07 |
以上元素項的默認值由solrconfig.xml配置文件定義。通常查詢時設置q=*:*,然后通過 fq 過濾條件來完成查詢,通過緩存提高查詢性能。
模糊查詢
Solr 的模糊查詢使用占位符來描述查詢規(guī)則,如下:
| 符號 | 描述 | 示例 |
|---|---|---|
| ? | 匹配單個字符 | te?t 會檢索到 test 和 text |
| * | 匹配零個或多個字符 | tes* 會檢索到 tes、test 等 |
查詢小區(qū)名稱中包含“嘉”的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE resblockName LIKE "%嘉%"
Solr 的模糊查詢?yōu)椋?/p>
fq=resblockName:*麗*
單精確值查詢
單精確值查詢是最簡單的查詢,類似于 SQL 中 = 操作符。查詢小區(qū) id 為 1111027377528 的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE resblockId = 1111027377528
Solr 中查詢?yōu)椋?/p>
fq=resblockId:1111027377528
多精確值查詢
多精確值查詢是單精確值查詢的擴展,格式為(value1 value2 ...),功能類似于 SQL 的 IN 操作符。查詢小區(qū) id 為 1111027377528 或者 1111047349969 的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE resblockId IN (1111027377528, 1111047349969)
Solr 中查詢?yōu)椋?/p>
fq=resblockId:(1111027377528 1111047349969)
范圍查詢
范圍查詢是查詢指定范圍的值(數(shù)字和時間),格式為[value1 TO value2],類似于 SQL 的 BETWEEN 操作符。查詢價格在 [2000, 3000] 的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE price BETWEEN 2000 AND 3000
Solr 中范圍查詢?yōu)椋?/p>
fq=price:[2000 TO 3000]
幾個特殊的范圍查詢:
| 條件 | 表達式 | 示例 |
|---|---|---|
| >= | [value TO *] | price:[2000 TO *] 價格 >=2000 |
| <= | [* TO value] | price:[* TO 2000] 價格 <=2000 |
布爾查詢
將基本查詢結合布爾查詢,就可以實現(xiàn)大部分復雜的檢索場景。布爾查詢支持以下幾種布爾操作:
| 操作邏輯 | 操作符 | 描述 |
|---|---|---|
| AND | &&+ | 邏輯與關系 |
| OR | 邏輯或關系 | |
| NOT | !- | 邏輯取反關系 |
查詢北京市價格區(qū)間在 [2000, 3000] 或者上海市價格區(qū)間在 [1500, 2000] 的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE (cityCode=110000 AND price BETWEEN 2000 AND 3000) OR (cityCode=310000 AND price BETWEEN 1500 AND 2000)
轉換為邏輯與布爾查詢:
fq=(cityCode:110000 && price:[2000 TO 3000])||(cityCode:310000 && price:[1500 TO 2000])
Group查詢
在實際中分組查詢比較常見,當然 Solr 也支持分組查詢。分組查詢語句由以下基本元素項組成(常用部分):
| 名稱 | 類型 | 描述 |
|---|---|---|
| group | boolean | 是否進行分組查詢 |
| group.field | string | 按該字段值進行分組 |
| group.limit | integer | 每組元素集大小,默認為 1 |
| group.offset | integer | 每組元素起始行數(shù) |
| group.sort | string | 組內元素排序規(guī)則,asc 和 desc |
查詢西二旗內價格最便宜小區(qū)的房源信息:
-- SQL表述
SELECT * FROM rooms WHERE bizcircleCode=611100314 GROUP BY resblockId ORDER BY price ASC LIMIT 1
Group 分組查詢?yōu)椋?/p>
q=*:*&fq=bizcircleCode:611100314&group=true&group.field=resblockId&group.limit=1&group.sort=size+desc
結果為:
"groups": [
{
"groupValue": 1111047349969,
"doclist": {
"numFound": 1, //每組房源數(shù)
"start": 0,
"docs": [
{
"resblockId": 1111047349969,
"resblockName": "融澤嘉園",
"bizcircleCode": [ 611100314 ],
"price": 2500
... ...
}]
... ...
}]
Facet查詢
在大多數(shù)情況下,Group 分組已經能滿足我們的需求,但是如果待分組字段為多值,Group 分組已經無能為力了,這時使用 Facet 就能輕松解決。
Solr 的 Facet 語句由以下基本元素構成(常用):
| 名稱 | 類型 | 描述 |
|---|---|---|
| facet | boolean | 是否進行 facet 查詢 |
| facet.field | string | 按該字段值進行 facet |
| facet.limit | integer | 每組元素集大小,默認為 1 |
| facet.offset | integer | 每組元素起始行數(shù) |
| facet.sort | string | 結果集排序規(guī)則,asc 和 desc |
| facet.mincount | integer | 每組元素最小數(shù)量 |
例如,統(tǒng)計每個商圈的房源分布情況并倒序排列,由于 bizcircleCode 字段為多值,F(xiàn)acet 查詢?yōu)椋?/p>
//此時不需要文檔信息,故rows=0
q=*:*&fq=cityCode:110000&facet=true&facet.field=bizcircleCode&facet.sort=desc&rows=0
結果如下:
"facet_fields": {
"bizcircleCode": [
"18335711",
1,
"18335745",
1,
"611100314",
3
]
}
空間檢索
Solr 的 geofilt 過濾器可以實現(xiàn) LBS 檢索,但要在schema.xml配置中將需檢索字段的字段類型設置為solr.LatLonType類型。geofilt 過濾器參數(shù)列表如下:
| 名稱 | 描述 | 示例 |
|---|---|---|
| d | 檢索距離,單位 km | 2 |
| pt | 檢索中心點坐標,格式:lat,lon | 40.074203,116.315445 |
| sfield | 檢索的索引字段 | location |
示例中的 location 字段,值為 “40.074203,116.315445”,類型配置為:
<fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
<field name="location" type="location"/>
則檢索坐標點40.074203,116.315445附近 2 公里的房源信息:
q=*:*&fq={!geofilt}&spatial=true&pt=40.074203,116.315445&sfield=location&d=2
函數(shù)
Solr 提供一些函數(shù)以實現(xiàn)邏輯或數(shù)學運算。其中常用 數(shù)學運算 函數(shù)列表如下:
| 函數(shù)名 | 描述 | 示例 |
|---|---|---|
| abs | 求絕對值 | abs(-5) |
| max | 返回最大值 | max(1, 2, 3) |
| min | 返回最小值 | min(1, 2, 3) |
| pow | 返回指數(shù)運算的結果 | pow(2, 2) |
| sqrt | 開方運算的結果 | sqrt(100) |
| product | 乘積 | product(1, 2, 3) |
| sub | 差 | sub(3, 2) |
| sum | 和 | sum(1, 2, 3) |
| div | 商 | div(4, 2) |
| log | 10 的對數(shù) | log(10) |
常用的 邏輯運算 函數(shù):
| 函數(shù)名 | 描述 | 示例 |
|---|---|---|
| def | 定義字段默認值 | def(price, 0) |
| if | if(test,value1,value2)test?value1:value2 | |
| exists | 字段是否存在 |
這些函數(shù)可以使用在返回值或者查詢條件上。例如返回每個房源的每平方米價格信息:
q=*:*&fl=*,avgPrice:div(price, size)
solarium客戶端
PHP 可以使用 solarium 客戶端,實現(xiàn) Solr 數(shù)據(jù)源的檢索,詳細使用說明 見這里。
配置基本
solarium 客戶端需要配置 Solr 的基本信息。如下:
//config.php
<?php
$solr = [
'endpoint' => [
'localhost' => [
'host' => 'solr.fanhaobai.com',
'port' => 80,
'path' => '/solr/rooms/',
]
]
];
基本查詢
solarium 提供的查詢方法較豐富,整理后如下表所示:
| 方法 | 所屬對象 | 描述 |
|---|---|---|
| createSelect | client | 創(chuàng)建查詢 query 對象 |
| select | client | 執(zhí)行查詢,返回 result 對象 |
| setQuery | query | 添加 query 條件 |
| setStart | query | 設置結果集起始行 |
| setRows | query | 設置結果集行數(shù) |
| setFields | query | 設置返回的字段 |
| addSort | query | 結果集排序規(guī)則 |
| createFilterQuery | query | 創(chuàng)建 filter query 對象 |
查詢北京市的所有房源信息,如下:
$client = new Solarium\Client($solr);
$query = $client->createSelect()->setStart(0)->setRows(20);
$query->createFilterQuery('rooms')->setQuery('cityCode:110000');
$result = $client->select($query);
Group查詢
solarium 提供的分組查詢方法如下表所示(常用):
| 方法 | 所屬對象 | 描述 |
|---|---|---|
| getGrouping | query | 創(chuàng)建分組 group 對象 |
| addQuery | group | 添加分組 query |
| setSort | group | 設置分組排序規(guī)則 |
| setLimit | group | 設置分組數(shù)量 |
| getGrouping | result | 獲取分組信息 |
獲取西二旗每個小區(qū)的房源分布信息,如下:
$client = new Solarium\Client($solr);
$query = $client->createSelect()->setStart(0)->setRows(20)->setQuery('bizcircleCode:611100314');
$group = $query->getGrouping();
$group->addField('resblockId')->setLimit(10)->setSort('price desc')->setNumberOfGroups(true);
$result = $client->select($query);
$groups = $result->getGrouping();
Facet查詢
solarium 提供的 Facet 查詢方法,如下表(常用):
| 方法 | 所屬對象 | 描述 |
|---|---|---|
| getFacetSet | query | 創(chuàng)建分組 facet 對象 |
| createFacetField | facet | 創(chuàng)建 facet 字段 |
| setField | facet | facet 分組字段 |
| setLimit | facet | 設置 facet 分組大小 |
獲取北京市每個商圈的房源分布信息,如下:
$client = new Solarium\Client($solr);
$query = $client->createSelect()->setStart(0)->setRows(20)->setQuery('bizcircleCode:611100314');
$facet = $query->getFacetSet();
$facet->createFacetField('bizcircle')->setField('bizcircleCode')->setLimit(10);
$result = $client->select($query);
總結
到這里,Solr 系列就整理完畢了,未涉及的部分后續(xù)接觸時再補充。這兩天利用休息時間充電,自己在 Solr 方面的技能也算是上了一個臺階了。