函数查询
函数查询使您能够使用一个或多个数字字段的实际值生成相关性得分。
函数查询使用函数。函数可以是常量(数字或字符串文本)、字段、另一个函数或参数替换参数。您可以使用这些函数修改结果对用户显示的排名。这些函数可用于根据用户的地理位置或其他一些计算更改结果的排名。
使用函数查询
函数必须表示为函数调用(例如,sum(a,b)
,而不是简单的 a+b
)。
有几种方法可以在 Solr 查询中使用函数查询
-
通过显式查询解析器,该解析器需要函数参数,例如
func
或frange
。例如q={!func}div(popularity,price)&fq={!frange l=1000}customer_ratings
-
在排序表达式中。例如
sort=div(popularity,price) desc, score desc
-
将函数结果作为伪字段添加到查询结果中的文档。例如,对于
&fl=sum(x, y),id,a,b,c,score&wt=xml
输出将为
... <str name="id">foo</str> <float name="sum(x,y)">40</float> <float name="score">0.343</float> ...
-
在明确用于指定函数的参数中使用,例如 eDisMax 查询解析器的
boost
参数,或 DisMax 查询解析器的bf
(提升函数)参数。(请注意,bf
参数实际上采用用空格分隔的函数查询列表,每个查询都有一个可选的提升值。使用bf
时,请确保消除单个函数查询中的任何内部空格)。例如q=dismax&bf="ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3"
-
使用
_val_
关键字在 Lucene 查询解析器中内联引入函数查询。例如q=_val_:mynumericfield _val_:"recip(rord(myfield),1,2,3)"
只建议使用具有快速随机访问的函数。
可用函数
下表总结了函数查询可用的函数。
childfield(field) 函数
通过 {!parent}
搜索时,返回匹配的子文档之一的给定字段的值。它只能在 sort
参数中使用。
语法示例
-
sort=childfield(name) asc
隐含地将$q
作为第二个参数,因此它假定q={!parent ..}..
; -
sort=childfield(field,$bjq) asc
引用单独的参数bjq={!parent ..}..
; -
sort=childfield(field,{!parent of=…}…) desc
允许内联块连接父查询
def 函数
def
是默认值的缩写。返回字段 "field" 的值,或者如果该字段不存在,则返回指定的默认值。产生 exists()==true
的第一个值。
语法示例
-
def(rating,5)
:此def()
函数返回评级,或者如果文档中未指定评级,则返回 5 -
def(myfield, 1.0):
等于if(exists(myfield),myfield,1.0)
dist 函数
返回 n 维空间中两个向量(点)之间的距离。获取幂次,加上两个或更多 ValueSource 实例,并计算两个向量之间的距离。每个 ValueSource 必须是一个数字。
必须传入偶数个 ValueSource 实例,并且该方法假定前半部分表示第一个向量,后半部分表示第二个向量。
语法示例
-
dist(2, x, y, 0, 0)
:计算每个文档中 (0,0) 和 (x,y) 之间的欧几里得距离。 -
dist(1, x, y, 0, 0)
:计算每个文档中 (0,0) 和 (x,y) 之间的曼哈顿(出租车)距离。 -
dist(2, x,y,z,0,0,0):
每个文档中 (0,0,0) 和 (x,y,z) 之间的欧几里得距离。 -
dist(1,x,y,z,e,f,g)
:其中每个字母都是字段名称,计算 (x,y,z) 和 (e,f,g) 之间的曼哈顿距离。
vectorSimilarity 函数
返回 n 维空间中两个 Knn 向量之间的相似性。获取输入向量元素编码、相似性度量以及两个 ValueSource 实例,并计算两个向量之间的相似性。
-
支持的编码有:
BYTE
、FLOAT32
。 -
支持的相似性有:
EUCLIDEAN
、COSINE
、DOT_PRODUCT
每个 ValueSource 必须是一个 knn 向量(字段或常量)。
语法示例
-
vectorSimilarity(FLOAT32, COSINE, [1,2,3], [4,5,6])
:计算每个文档中 [1, 2, 3] 和 [4, 5, 6] 之间的余弦相似性。 -
vectorSimilarity(FLOAT32, DOT_PRODUCT, vectorField1, vectorField2)
:计算每个文档中“vectorField1”和“vectorField2”中向量的点积相似度。 -
vectorSimilarity(BYTE, EUCLIDEAN, [1,5,4,3], vectorField)
:计算每个文档中“vectorField”中向量和常量向量 [1, 5, 4, 3] 之间的欧几里得相似度。
docfreq(field,val) 函数
返回包含该字段中词条的文档数。这是一个常量(索引中所有文档的值相同)。
如果词条更复杂,你可以引用它,或者对词条值进行参数替换。
语法示例
-
docfreq(text,'solr')
-
…&defType=func
&q=docfreq(text,$myterm)&myterm=solr
field 函数
返回具有指定名称的字段的数字 docValues 或索引值。在其最简单的(单参数)形式中,此函数只能用于单值字段,并且可以使用字段名称作为字符串进行调用,或者对于大多数常规字段名称,只需使用字段名称本身,而无需使用 field(…)
语法。
在使用 docValues 时,可以指定一个可选的第二个参数来选择多值字段的 min
或 max
值。
对于字段中没有值的文档,将返回 0。
语法示例 这 3 个示例是等效的
-
myFloatFieldName
-
field(myFloatFieldName)
-
field("myFloatFieldName")
当你的字段名称不典型时,最后一种形式很方便
-
field("my complex float fieldName")
对于多值 docValues 字段
-
field(myMultiValuedFloatField,min)
-
field(myMultiValuedFloatField,max)
hsin 函数
Haversine 距离计算沿着球体行进时球体上两点之间的距离。值必须以弧度为单位。hsin
还接受一个布尔参数来指定函数是否应将其输出转换为弧度。
语法示例
-
hsin(2, true, x, y, 0, 0)
idf 函数
逆文档频率;衡量术语在所有文档中是否常见或罕见。通过将文档总数除以包含该术语的文档数,然后取该商的对数来获得。另请参见tf
。
语法示例
-
idf(fieldName,'solr')
:衡量术语'solr'
在fieldName
中出现的频率的倒数。
if 函数
启用条件函数查询。在if(test,value1,value2)
中
-
test
是逻辑值或返回逻辑值(TRUE 或 FALSE)的表达式的引用。 -
value1
是当test
产生 TRUE 时由函数返回的值。 -
value2
是当test
产生 FALSE 时由函数返回的值。
表达式可以是输出布尔值的任何函数,甚至可以是返回数字值的函数,在这种情况下,值 0 将被解释为 false,或字符串,在这种情况下,空字符串将被解释为 false。
语法示例
-
if(termfreq (cat,'electronics'),popularity,42)
:此函数检查每个文档以查看它是否在cat
字段中包含术语“electronics”。如果包含,则返回popularity
字段的值,否则返回42
的值。
linear 函数
实现m*x+c
,其中m
和c
是常量,x
是任意函数。这等效于sum(product(m,x),c)
,但效率稍高,因为它作为单个函数实现。
语法示例
-
linear(x,m,c)
-
linear(x,2,4)
:返回2*x+4
map 函数
将输入函数x
的任何值映射到包含在min
和max
(包括)之间的指定target
。参数min
和max
必须是常量。参数target
和default
可以是常量或函数。
如果x
的值不介于min
和max
之间,则返回x
的值,或者如果指定为第 5 个参数,则返回默认值。
语法示例
-
map(x,min,max,target)
-
map(x,0,0,1)
:将任何 0 值更改为 1。这在处理默认 0 值时很有用。
-
-
map(x,min,max,target,default)
-
map(x,0,100,1,-1)
:将0
和100
之间的任何值更改为1
,并将所有其他值更改为-1
。 -
map(x,0,100,sum(x,599),docfreq(text,solr))
:将0
和100
之间的任何值更改为 x+599,并将所有其他值更改为术语“solr”在字段文本中的频率。
-
max 函数
返回多个嵌套函数或常量的最大数值,这些函数或常量指定为参数:max(x,y,…)
。max
函数还可以用于将另一个函数或字段“底部”固定在某个指定常量上。
使用 field(myfield,max)
语法来 选择单个多值字段的最大值。
语法示例
-
max(myfield,myotherfield,0)
min 函数
返回多个嵌套函数或常量的最小数值,这些函数或常量指定为参数:min(x,y,…)
。min
函数还可以用于使用常量为函数提供“上限”。
使用 field(myfield,min)
语法选择单个多值字段的最小值。
语法示例
-
min(myfield,myotherfield,0)
ms 函数
返回其参数之间的时间差(以毫秒为单位)。日期相对于 Unix 或 POSIX 时间纪元,即 1970 年 1 月 1 日 UTC 午夜。
参数可以是 DatePointField
、TrieDateField
的名称,也可以是基于 常量日期或 NOW
的日期数学运算。
-
ms()
:等效于ms(NOW)
,即自纪元以来的毫秒数。 -
ms(a):
返回参数表示的自纪元以来的毫秒数。 -
ms(a,b)
:返回 b 在 a 之前发生的毫秒数(即 a - b)
语法示例
-
ms(NOW/DAY)
-
ms(2000-01-01T00:00:00Z)
-
ms(mydatefield)
-
ms(NOW,mydatefield)
-
ms(mydatefield, 2000-01-01T00:00:00Z)
-
ms(datefield1, datefield2)
ord 函数
返回 Lucene 索引顺序(按 unicode 值按字典顺序排列)中该字段的索引术语列表中索引字段值的序号,从 1 开始。
换句话说,对于给定的字段,所有值按字典顺序排列;然后此函数返回该排序中特定值的偏移量。该字段每个文档必须最多有一个值(非多值)。对于字段中没有值的文档,返回 0
。
ord() 取决于索引中的位置,当插入或删除其他文档时可能会更改。 |
另请参见下面的 rord
。
语法示例
-
ord(myIndexedField)
-
如果特定字段 X 只有三个值(“apple”、“banana”、“pear”),则对于包含“apple”的文档,
ord(X)
将为1
,对于包含“banana”的文档,将为2
,依此类推。
payload 函数
返回从指定术语的解码有效负载计算的浮点值。
返回值使用解码有效负载的 min
、max
或 average
计算。可以使用特殊 first
函数代替其他函数,以短路术语枚举并仅返回第一个术语的解码有效负载。
指定字段必须具有浮点或整数有效负载编码功能(通过 DelimitedPayloadTokenFilter
或 NumericPayloadTokenFilter
)。如果找不到术语的有效负载,则返回默认值。
-
payload(field_name,term)
:默认值为 0.0,使用average
函数。 -
payload(field_name,term,default_value)
:默认值可以是常量、字段名称或另一个返回浮点的函数。使用average
函数。 -
payload(field_name,term,default_value,function)
:函数值可以是min
、max
、average
或first
。
语法示例
-
payload(payloaded_field_dpf,term,0.0,first)
query 函数
返回给定子查询的分数,或不匹配查询的文档的默认值。通过参数取消引用 $otherparam
或通过 v
键在 本地参数 中直接指定查询字符串,支持任何类型的子查询。
语法示例
-
query(subquery, default)
-
q=product (popularity,query({!dismax v='solr rocks'})
:返回流行度和 DisMax 查询分数的乘积。 -
q=product (popularity,query($qq))&qq={!dismax}solr rocks
:等效于上一个查询,使用参数取消引用。 -
q=product (popularity,query($qq,0.1))&qq={!dismax}solr rocks
:为与 DisMax 查询不匹配的文档指定 0.1 的默认分数。
recip 函数
使用 recip(x,m,a,b)
执行倒数函数,实现 a/(m*x+b)
,其中 m,a,b
是常量,而 x
是任意复杂函数。
当 a
和 b
相等,且 x>=0
时,此函数的最大值为 1
,随着 x
的增加而下降。同时增加 a
和 b
的值会导致整个函数向曲线的平坦部分移动。当 x 为 rord(datefield)
时,这些属性可以使其成为提升较新文档的理想函数。
语法示例
-
recip(myfield,m,a,b)
-
recip(rord
(creationDate), 1,1000,1000)
scale 函数
缩放函数 x
的值,使其介于指定的 minTarget
和 maxTarget
(包括)之间。当前实现遍历所有函数值以获取最小值和最大值,以便选择正确的比例。
当前实现无法区分文档何时被删除或文档没有值。它对这些情况使用 0.0
值。这意味着,如果值通常都大于 0.0
,则最终仍可能将 0.0
作为要映射的最小值。在这些情况下,可以使用适当的 map()
函数作为解决方法,将 0.0
更改为实际范围内的值,如下所示:scale(map(x,0,0,5),1,2)
语法示例
-
scale(x, minTarget, maxTarget)
-
scale(x,1,2)
:缩放 x 的值,使所有值介于 1 和 2(包括)之间。
sqedist 函数
平方欧几里得距离计算 2 范数(欧几里得距离),但不取平方根,从而节省了一项相当昂贵的操作。通常情况下,关心欧几里得距离的应用程序不需要实际距离,而是可以使用距离的平方。必须传入偶数个 ValueSource 实例,并且该方法假定前半部分表示第一个向量,后半部分表示第二个向量。
语法示例
-
sqedist(x_td, y_td, 0, 0)
strdist 函数
计算两个字符串之间的距离。使用 Lucene 拼写检查器 StringDistance
接口,并支持该包中提供的所有实现,此外还允许应用程序通过 Solr 的资源加载功能插入自己的实现。strdist
采用 (string1, string2, 距离度量)。
距离度量的可能值为
-
jw: Jaro-Winkler
-
edit: Levenstein 或编辑距离
-
ngram: 如果指定 NGramDistance,还可以选择传入 ngram 大小。默认为 2。
-
FQN: StringDistance 接口实现的完全限定类名。必须有无参数构造函数。
语法示例
-
strdist("SOLR",id,edit)
sum 函数
返回多个值或函数的总和,这些值或函数用逗号分隔的列表指定。add(…)
可用作此函数的别名。
语法示例
-
sum(x,y,…)
-
sum(x,1)
-
sum(sqrt(x),log(y),z,0.5)
-
add(x,y)
sumtotaltermfreq 函数
返回整个索引中字段中所有词条的 totaltermfreq
值的总和(即该字段的已索引词条数)。(将 sumtotaltermfreq
别名为 sttf
。)
语法示例 如果 doc1:(fieldX:A B C) 和 doc2:(fieldX:A A A A)
-
docFreq(fieldX:A)
= 2(A 出现于 2 个文档中) -
freq(doc1, fieldX:A)
= 4(A 在 doc 2 中出现 4 次) -
totalTermFreq(fieldX:A)
= 5(A 在所有文档中出现 5 次) -
sumTotalTermFreq(fieldX)
= 7 在fieldX
中,有 5 个 A,1 个 B,1 个 C
tf 函数
词频;使用字段的 相似性,返回给定词条的词频因子。tf-idf
值与单词在文档中出现的次数成正比增加,但会因单词在文档中的频率而抵消,这有助于控制某些单词通常比其他单词更常见这一事实。另请参见 idf
。
语法示例
-
tf(text,'solr')
布尔函数
以下函数为布尔函数 - 它们返回真或假。它们主要用作 if
函数的第一个参数,其中一些可以组合。如果在其他地方使用,它将产生 '1' 或 '0'。
and 函数
当且仅当其所有操作数都计算为真时,返回真值。
语法示例
-
and(not(exists(popularity)),exists(price))
:对于在price
字段中有值但popularity
字段中没有值的任何文档,返回true
。
xor 函数
逻辑异或,或一个或另一个,但不能同时存在。
语法示例
-
xor(field1,field2)
如果field1
或field2
为真,则返回true
;如果两者都为真,则返回 FALSE。
exists 函数
如果字段的任何成员存在,则返回 true
。
语法示例
-
exists(author)
:对于在 "author" 字段中有值的任何文档,返回true
。 -
exists(query(price:5.00))
:如果 "price" 匹配 "5.00",则返回true
。
函数查询示例
为了让你更好地理解如何在 Solr 中使用函数查询,假设一个索引存储了某些假设框的维度(以米为单位)x、y、z,这些框的任意名称存储在字段 boxname
中。假设我们要搜索名称匹配 findbox
的框,但根据框的体积进行排名。查询参数将是
q=boxname:findbox _val_:"product(x,y,z)"
此查询将根据体积对结果进行排名。为了获得计算出的体积,你需要请求 score
,其中将包含结果体积
&fl=*, score
假设你还有一个字段,将框的重量存储为 weight
。要按框的密度排序并在 score 中返回密度值,你可以提交以下查询
http://localhost:8983/solr/collection_name/select?q=boxname:findbox _val_:"div(weight,product(x,y,z))"&fl=boxname x y z weight score
按函数排序
你可以按函数的输出对查询结果进行排序。例如,要按距离对结果进行排序,你可以输入
http://localhost:8983/solr/collection_name/select?q=*:*&sort=dist(2, point1, point2) desc
按函数排序还支持伪字段:字段可以动态生成,并返回结果,就好像它是索引中的普通字段一样。例如,
&fl=id,sum(x, y),score&wt=xml
将返回
<str name="id">foo</str>
<float name="sum(x,y)">40</float>
<float name="score">0.343</float>