函数查询
函数查询允许您使用一个或多个数值字段的实际值生成相关性分数。
函数查询由 DisMax 查询解析器、扩展 DisMax (eDisMax) 查询解析器 和 标准查询解析器 支持。
函数查询使用函数。函数可以是常量(数值或字符串文字)、字段、另一个函数或参数替换参数。您可以使用这些函数来修改用户结果的排名。这些可以用来根据用户的位置或其他一些计算来更改结果的排名。
使用函数查询
函数必须表示为函数调用(例如,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
是 default(默认值)的缩写。返回字段 "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 向量之间的相似度。此函数有两个变体。
vectorSimilarity(vector1, vector2)
此函数接受两个向量作为输入:第一个参数必须是 DenseVectorField
的名称。第二个参数可以是第二个 DenseVectorField
的名称,也可以是常量向量。
如果指定了两个字段名,则它们必须配置相同的 vectorDimensions
、vectorEncoding
和 similarityFunction
。如果指定了常量向量,则将使用第一个参数指定的字段上配置的 vectorEncoding
进行解析,并且必须具有相同的维度。
语法示例
-
vectorSimilarity(vectorField1, vectorField2)
:计算每个文档的向量字段vectorField1
和vectorField2
之间配置的相似度。 -
vectorSimilarity(vectorField1, [1,2,3,4])
:计算每个文档的向量字段vectorField1
和[1, 2, 3, 4]
之间配置的相似度。
只有遵循推荐字段命名约定的字段名才能保证使用此语法。在函数查询中使用时需要 field("…") 语法的非典型字段名必须使用下面描述的 vectorSimilarity(…) 函数的更复杂的 4 参数变体语法。 |
vectorSimilarity(ENCODING, SIMILARITY_FUNCTION, vector1, vector2)
输入向量元素编码、相似度度量以及两个 ValueSource 实例(DenseVectorField
或常量向量),并计算两个向量之间的相似度。
-
支持的编码是:
BYTE
、FLOAT32
-
这用于解析任何常量向量参数
-
-
支持的相似度是:
EUCLIDEAN
、COSINE
、DOT_PRODUCT
语法示例
-
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')
:衡量fieldName
中词项'solr'
出现频率的倒数。
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
的任何值映射到指定的 target
,这些值落在 min
和 max
(包括)之间。参数 min
和 max
必须是常量。参数 target
和 default
可以是常量或函数。
如果 x
的值未落在 min
和 max
之间,则返回 x
的值,或者如果指定了第五个参数,则返回默认值。
语法示例
-
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 时间纪元,即 UTC 1970 年 1 月 1 日午夜。
参数可以是 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
作为要映射的 min
值。在这些情况下,可以使用适当的 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:Levenshtein 或编辑距离
-
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 在文档 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')
布尔函数
以下函数是布尔函数,它们返回 true 或 false。它们主要用作 if
函数的第一个参数,其中一些可以组合使用。如果在其他地方使用,它将产生“1”或“0”。
and 函数
当且仅当其所有操作数的值都为 true 时,返回 true 的值。
语法示例
-
and(not(exists(popularity)),exists(price))
:对于price
字段中具有值但在popularity
字段中没有值的任何文档,返回true
。
xor 函数
逻辑异或,即一个或另一个,但不能同时为真。
语法示例
-
如果
field1
或field2
为 true,则xor(field1,field2)
返回true
;如果两者都为 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 中返回密度值,您将提交以下查询
https://127.0.0.1:8983/solr/collection_name/select?q=boxname:findbox _val_:"div(weight,product(x,y,z))"&fl=boxname x y z weight score
按函数排序
您可以根据函数的输出来排序查询结果。例如,要按距离排序结果,您可以输入
https://127.0.0.1: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>