Solr查询:函数查询详解
概述
函数查询使您能够使用一个或多个数值字段的实际值来生成相关性分数。
函数查询由DisMax查询解析器、eDisMax查询解析器和标准查询解析器支持。
函数查询使用函数。这些函数可以是常量(数值或字符串字面量)、字段、另一个函数或参数替换参数。您可以使用这些函数来修改用户的结果排序。这些可用于基于用户位置或其他计算改变结果排序。
使用函数查询
函数必须表示为函数调用(例如,sum(a,b)
而不是简单的a+b
)。
在Solr查询中使用函数查询有几种方式:
- 通过期望函数参数的显式查询解析器,如
func
或frange
。
例如:
1 | q={!func}div(popularity,price)&fq={!frange l=1000}customer_ratings |
- 在排序表达式中。
例如:
1 | sort=div(popularity,price) desc, score desc |
- 将函数的结果作为伪字段添加到查询结果中的文档。
例如:
1 | &fl=sum(x, y),id,a,b,c,score&wt=xml |
输出将是:
1 | ... |
- 在明确用于指定函数的参数中使用,如eDisMax查询解析器的
boost
参数,或DisMax查询解析器的bf
(提升函数)参数。
(注意bf
参数实际上接受由空白字符分隔的函数查询列表,每个都有可选的提升。使用bf
时确保消除单个函数查询中的任何内部空白字符)。
例如:
1 | q=dismax&bf="ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3" |
- 在Lucene查询解析器中使用
_val_
关键字内联引入函数查询。
例如:
1 | q=_val_:mynumericfield _val_:"recip(rord(myfield),1,2,3)" |
仅建议使用具有快速随机访问的函数。
可用函数
下表总结了函数查询可用的函数。
此外,您可以使用表达式值源解析器用少量JavaScript编写自定义函数。
abs函数
返回指定值或函数的绝对值。
语法示例
abs(x)
abs(-5)
childfield(field)函数
在使用{!parent}
搜索时返回匹配子文档之一的给定字段值。它只能在sort
参数中使用。
语法示例
sort=childfield(name) asc
将$q
作为第二个参数,因此假设q={!parent ..}..
;sort=childfield(field,$bjq) asc
引用单独的参数bjq={!parent ..}..
;sort=childfield(field,{!parent of=...}...) desc
允许内联块连接父查询
concat函数
连接给定的字符串字段、字面量和其他函数。
语法示例
concat(name," ",$param,def(opt,"-"))
“constant”函数
指定浮点常量。
语法示例
1.5
def函数
def
是default的简写。返回字段”field”的值,或如果字段不存在,返回指定的默认值。产生第一个exists()==true
的值。
语法示例
def(rating,5)
:此def()
函数返回rating,或如果文档中没有指定rating,返回5def(myfield, 1.0)
:等价于if(exists(myfield),myfield,1.0)
div函数
将一个值或函数除以另一个。div(x,y)
将x
除以y
。
语法示例
div(1,y)
div(sum(x,100),max(y,1))
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("...")
语法的非典型字段名必须使用下面描述的更复杂的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函数
哈弗辛距离计算在球面上沿球面行进时两点之间的距离。值必须以弧度为单位。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
log函数
返回指定函数的以10为底的对数。
语法示例
log(x)
log(sum(x,100))
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)
maxdoc函数
返回索引中的文档数,包括标记为已删除但尚未清除的文档。这是常量(索引中所有文档的相同值)。
语法示例
maxdoc()
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)
norm(field)函数
返回索引中为指定字段存储的”范数”。这是索引时提升和长度标准化因子的乘积,根据字段的相似性。
语法示例
norm(fieldName)
numdocs函数
返回索引中的文档数,不包括标记为已删除但尚未清除的文档。这是常量(索引中所有文档的相同值)。
语法示例
numdocs()
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)
pow函数
将指定底数提升到指定幂。pow(x,y)
将x
提升到y
的幂。
语法示例
pow(x,y)
pow(x,log(y))
pow(x,0.5)
:与sqrt
相同
product函数
返回多个值或函数的乘积,这些在逗号分隔列表中指定。mul(...)
也可用作此函数的别名。
语法示例
product(x,y,...)
product(x,2)
mul(x,y)
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)
rord函数
返回与ord
返回的相反排序。
语法示例
rord(myDateField)
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)
sqrt函数
返回指定值或函数的平方根。
语法示例
sqrt(x)
sqrt(100)
sqrt(sum(x,100))
strdist函数
计算两个字符串之间的距离。使用Lucene拼写检查器StringDistance
接口并支持该包中所有可用的实现,以及允许应用程序通过Solr的资源加载功能插入自己的实现。strdist
接受(string1, string2, distance measure)。
距离度量的可能值为:
- jw:Jaro-Winkler
- edit:Levenshtein或编辑距离
- ngram:NGramDistance,如果指定,也可以可选地传入ngram大小。默认为2。
- FQN:StringDistance接口实现的完全限定类名。必须有无参构造函数。
语法示例
strdist("SOLR",id,edit)
sub函数
从sub(x,y)
返回x-y
。
语法示例
sub(myfield,myfield2)
sub(100, sqrt(myfield))
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
termfreq函数
返回该文档字段中术语出现的次数。
语法示例
termfreq(text,'memory')
tf函数
术语频率;使用字段的相似性返回给定术语的术语频率因子。tf-idf
值与词在文档中出现的次数成比例增加,但被词在文档中的频率抵消,这有助于控制某些词通常比其他词更常见的事实。另请参阅idf
。
语法示例
tf(text,'solr')
top函数
使函数查询参数从包含索引所有部分的顶级IndexReader派生其值。例如,单个段中值的序数与完整索引中该相同值的序数将不同。
ord()
和rord()
函数隐式使用top()
,因此ord(foo)
等价于top(ord(foo))
。
totaltermfreq函数
返回术语在整个索引的字段中出现的次数。(将totaltermfreq
别名为ttf
。)
语法示例
ttf(text,'memory')
布尔函数
以下函数是布尔函数——它们返回true或false。它们主要用作if
函数的第一个参数,其中一些可以组合。如果在其他地方使用,将产生’1’或’0’。
and函数
当且仅当其所有操作数求值为true时返回true值。
语法示例
and(not(exists(popularity)),exists(price))
:为任何在price
字段中有值但在popularity
字段中没有值的文档返回true
。
or函数
逻辑析取。
语法示例
or(value1,value2)
:如果value1
或value2
为true,则为true
。
xor函数
逻辑异或,一个或另一个但不是两个。
语法示例
xor(field1,field2)
:如果field1
或field2
为true则返回true
;如果两者都为true则为FALSE。
not函数
包装函数的逻辑非值。
语法示例
not(exists(author))
:仅当exists(author)
为false时为true
。
exists函数
如果字段的任何成员存在,返回true
。
语法示例
exists(author)
:为在”author”字段中有值的任何文档返回true
。exists(query(price:5.00))
:如果”price”匹配”5.00”,返回true
。
比较函数
gt
、gte
、lt
、lte
、eq
5个比较函数:大于、大于等于、小于、小于等于、等于。eq
不仅适用于数字,基本上适用于任何值,如字符串字段。
语法示例
if(lt(ms(mydatefield),315569259747),0.8,1)
转换为此伪代码:if mydatefield < 315569259747 then 0.8 else 1
isnan函数
如果值是浮点NaN(非数字),返回true
。
语法示例
isnan(myfield)
:为在”myfield”中存储NaN的任何文档返回true
。isnan(12.3456)
:返回false
。isnan(0)
:返回false
。isnan(div(0,0))
:返回true
(因为0除以0未定义并返回NaN)。
函数查询示例
为了更好地理解如何在Solr中使用函数查询,假设索引存储一些假设框的米为单位的尺寸x,y,z,任意名称存储在字段boxname
中。假设我们要搜索匹配名称findbox
的框但根据框的体积排序。查询参数将是:
1 | q=boxname:findbox _val_:"product(x,y,z)" |
此查询将根据体积对结果排序。为了获得计算的体积,您需要请求score
,它将包含结果体积:
1 | &fl=*, score |
假设您还有一个存储框重量的字段weight
。要按框的密度排序并在分数中返回密度值,您将提交以下查询:
1 | http://localhost:8983/solr/collection_name/select?q=boxname:findbox _val_:"div(weight,product(x,y,z))"&fl=boxname x y z weight score |
按函数排序
您可以按函数的输出对查询结果排序。例如,要按距离对结果排序,您可以输入:
1 | http://localhost:8983/solr/collection_name/select?q=*:*&sort=dist(2, point1, point2) desc |
按函数排序还支持伪字段:字段可以动态生成并返回结果,就像它是索引中的正常字段一样。例如,
&fl=id,sum(x, y),score&wt=xml
将返回:
1 | <str name="id">foo</str> |
本文档翻译自Apache Solr官方参考指南,旨在为中文用户提供完整的函数查询使用指南。