Solr的使用 — 检索

原文:https://www.fanhaobai.com/2017/08/solr-search.html

本文是延续 Solr的使用 系列,前一篇文章已经讲了 Solr 的部署和数据推送,这里主要以示例方式讲述 Solr 的常见查询语法,同时介绍如何使用 PHP 语言的客户端 solarium 同 Solr 集群进行数据交互。

想要详细地了解 Solr 查询语法,可参考 官方wiki

数据格式

用于示例的数据,我已经推送到了 Solr ,见这里。数据 Core 为 rooms,数据格式形如:

[{
    "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 指定结果集起始返回的行数,默认 0 0
rows 指定结果集返回的行数,默认 10 15
sort 结果集的排序规则 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

函数:fl 还支持使用 Solr 内置函数,例如根据单价算总价:

fl=id,total:product(size,price)

fq

fq 过滤查询条件,可充分利用 cache,所以可以利用 fq 提高检索性能。

sort

sort 指定结果集的排序规则,格式为<fieldName>+<sort>,支持 asc 和 desc 两种排序规则。例如按照价格倒序排列:

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 的模糊查询使用占位符来描述查询规则,如下:

符号 描述 示例
? 匹配单个字符 te?t 会检索到 test 和 text
* 匹配零个或多个字符 tes* 会检索到 tes、test 等

查询小区名称中包含“嘉”的房源信息:

-- SQL表述
SELECT * FROM rooms WHERE resblockName LIKE "%嘉%"

Solr 的模糊查询为:

fq=resblockName:*丽*

单精确值查询

单精确值查询是最简单的查询,类似于 SQL 中 = 操作符。查询小区 id 为 1111027377528 的房源信息:

-- SQL表述
SELECT * FROM rooms WHERE resblockId = 1111027377528

Solr 中查询为:

fq=resblockId:1111027377528

多精确值查询

多精确值查询是单精确值查询的扩展,格式为(value1 value2 ...),功能类似于 SQL 的 IN 操作符。查询小区 id 为 1111027377528 或者 1111047349969 的房源信息:

-- SQL表述
SELECT * FROM rooms WHERE resblockId IN (1111027377528, 1111047349969)

Solr 中查询为:

fq=resblockId:(1111027377528 1111047349969)

范围查询

范围查询是查询指定范围的值(数字和时间),格式为[value1 TO value2],类似于 SQL 的 BETWEEN 操作符。查询价格在 [2000, 3000] 的房源信息:

-- SQL表述
SELECT * FROM rooms WHERE price BETWEEN 2000 AND 3000

Solr 中范围查询为:

fq=price:[2000 TO 3000]

几个特殊的范围查询:

条件 表达式 示例
>= [value TO *] price:[2000 TO *] 价格 >=2000
<= [* TO value] price:[* TO 2000] 价格 <=2000

布尔查询

将基本查询结合布尔查询,就可以实现大部分复杂的检索场景。布尔查询支持以下几种布尔操作:

操作逻辑 操作符 描述
AND &&+ 逻辑与关系
OR 逻辑或关系
NOT !- 逻辑取反关系

查询北京市价格区间在 [2000, 3000] 或者上海市价格区间在 [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 每组元素起始行数
group.sort string 组内元素排序规则,asc 和 desc

查询西二旗内价格最便宜小区的房源信息:

-- SQL表述
SELECT * FROM rooms WHERE bizcircleCode=611100314 GROUP BY resblockId ORDER BY price ASC LIMIT 1

Group 分组查询为:

q=*:*&fq=bizcircleCode:611100314&group=true&group.field=resblockId&group.limit=1&group.sort=size+desc

结果为:

"groups": [
{
    "groupValue": 1111047349969,
    "doclist": {
    "numFound": 1,                 //每组房源数
    "start": 0,
    "docs": [
    {
        "resblockId": 1111047349969,
        "resblockName": "融泽嘉园",
        "bizcircleCode": [ 611100314 ],
        "price": 2500
        ... ...
    }]
    ... ...
}]

Facet查询

在大多数情况下,Group 分组已经能满足我们的需求,但是如果待分组字段为多值,Group 分组已经无能为力了,这时使用 Facet 就能轻松解决。

Solr 的 Facet 语句由以下基本元素构成(常用):

名称 类型 描述
facet boolean 是否进行 facet 查询
facet.field string 按该字段值进行 facet
facet.limit integer 每组元素集大小,默认为 1
facet.offset integer 每组元素起始行数
facet.sort string 结果集排序规则,asc 和 desc
facet.mincount integer 每组元素最小数量

例如,统计每个商圈的房源分布情况并倒序排列,由于 bizcircleCode 字段为多值,Facet 查询为:

//此时不需要文档信息,故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 过滤器可以实现 LBS 检索,但要在schema.xml配置中将需检索字段的字段类型设置为solr.LatLonType类型。geofilt 过滤器参数列表如下:

名称 描述 示例
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

函数

Solr 提供一些函数以实现逻辑或数学运算。其中常用 数学运算 函数列表如下:

函数名 描述 示例
abs 求绝对值 abs(-5)
max 返回最大值 max(1, 2, 3)
min 返回最小值 min(1, 2, 3)
pow 返回指数运算的结果 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 的对数 log(10)

常用的 逻辑运算 函数:

函数名 描述 示例
def 定义字段默认值 def(price, 0)
if if(test,value1,value2)test?value1:value2
exists 字段是否存在

这些函数可以使用在返回值或者查询条件上。例如返回每个房源的每平方米价格信息:

q=*:*&fl=*,avgPrice:div(price, size)

solarium客户端

PHP 可以使用 solarium 客户端,实现 Solr 数据源的检索,详细使用说明 见这里

配置基本

solarium 客户端需要配置 Solr 的基本信息。如下:

//config.php
<?php
$solr = [
    'endpoint' => [
        'localhost' => [
            'host' => 'solr.fanhaobai.com',
            'port' => 80,
            'path' => '/solr/rooms/',
        ]
    ]
];

基本查询

solarium 提供的查询方法较丰富,整理后如下表所示:

方法 所属对象 描述
createSelect client 创建查询 query 对象
select client 执行查询,返回 result 对象
setQuery query 添加 query 条件
setStart query 设置结果集起始行
setRows query 设置结果集行数
setFields query 设置返回的字段
addSort query 结果集排序规则
createFilterQuery query 创建 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 创建分组 group 对象
addQuery group 添加分组 query
setSort group 设置分组排序规则
setLimit group 设置分组数量
getGrouping result 获取分组信息

获取西二旗每个小区的房源分布信息,如下:

$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 创建分组 facet 对象
createFacetField facet 创建 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 系列就整理完毕了,未涉及的部分后续接触时再补充。这两天利用休息时间充电,自己在 Solr 方面的技能也算是上了一个台阶了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容