函数查询

函数查询允许您使用一个或多个数值字段的实际值生成相关性分数。

函数查询使用函数。函数可以是常量(数值或字符串文字)、字段、另一个函数或参数替换参数。您可以使用这些函数来修改用户结果的排名。这些可以用来根据用户的位置或其他一些计算来更改结果的排名。

使用函数查询

函数必须表示为函数调用(例如,sum(a,b) 而不是简单的 a+b)。

在 Solr 查询中有几种使用函数查询的方法

  • 通过显式查询解析器,该解析器需要函数参数,例如 funcfrange。例如

    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)"

仅建议使用具有快速随机访问的函数。

可用函数

下表总结了可用于函数查询的函数。

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() 函数返回评分,如果文档中未指定评分,则返回 5

  • def(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 的名称,也可以是常量向量。

如果指定了两个字段名,则它们必须配置相同的 vectorDimensionsvectorEncodingsimilarityFunction。如果指定了常量向量,则将使用第一个参数指定的字段上配置的 vectorEncoding 进行解析,并且必须具有相同的维度。

语法示例

  • vectorSimilarity(vectorField1, vectorField2):计算每个文档的向量字段 vectorField1vectorField2 之间配置的相似度。

  • vectorSimilarity(vectorField1, [1,2,3,4]):计算每个文档的向量字段 vectorField1[1, 2, 3, 4] 之间配置的相似度。

只有遵循推荐字段命名约定的字段名才能保证使用此语法。在函数查询中使用时需要 field("…​") 语法的非典型字段名必须使用下面描述的 vectorSimilarity(…​) 函数的更复杂的 4 参数变体语法。

vectorSimilarity(ENCODING, SIMILARITY_FUNCTION, vector1, vector2)

输入向量元素编码、相似度度量以及两个 ValueSource 实例(DenseVectorField 或常量向量),并计算两个向量之间的相似度。

  • 支持的编码是:BYTEFLOAT32

    • 这用于解析任何常量向量参数

  • 支持的相似度是:EUCLIDEANCOSINEDOT_PRODUCT

语法示例

  • vectorSimilarity(FLOAT32, COSINE, [1,2,3], [4,5,6]):计算每个文档的 [1, 2, 3][4, 5, 6] 之间的余弦相似度。

  • vectorSimilarity(FLOAT32, DOT_PRODUCT, vectorField1, vectorField2):计算每个文档的 vectorField1vectorField2 中的向量之间的点积相似度。

  • 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 时,可以指定一个可选的第二个参数来选择多值字段的 minmax 值。

对于字段中没有值的文档,返回 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,其中 mc 是常量,而 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 的任何值映射到指定的 target,这些值落在 minmax(包括)之间。参数 minmax 必须是常量。参数 targetdefault 可以是常量或函数。

如果 x 的值未落在 minmax 之间,则返回 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):将 0100 之间的任何值更改为 1,并将所有其他值更改为 -1

    • map(x,0,100,sum(x,599),docfreq(text,solr)):将 0100 之间的任何值更改为 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 时间纪元,即 UTC 1970 年 1 月 1 日午夜。

参数可以是 DatePointFieldTrieDateField 的名称,也可以是基于常量日期或 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”。根据字段的 Similarity,这是索引时间提升和长度归一化因子的乘积。

语法示例

  • norm(fieldName)

numdocs 函数

返回索引中的文档数,不包括那些标记为已删除但尚未清除的文档。这是一个常量(索引中所有文档的值都相同)。

语法示例

  • numdocs()

ord 函数

返回指定字段值在 Lucene 索引顺序(按 Unicode 值字典排序)的索引词列表中的序号,从 1 开始。

换句话说,对于给定的字段,所有值都按字典顺序排序;此函数返回特定值在此排序中的偏移量。该字段每个文档最多只能有一个值(不是多值)。对于字段中没有值的文档,返回 0

ord() 取决于索引中的位置,并且当插入或删除其他文档时可能会更改。

另请参见下面的 rord

语法示例

  • ord(myIndexedField)

  • 如果特定字段 X 只有三个值(“apple”、“banana”、“pear”),那么对于包含“apple”的文档,ord(X) 将为 1;对于包含“banana”的文档,将为 2,依此类推。

payload 函数

返回从指定词条的解码有效负载计算得出的浮点值。

返回值是使用解码有效负载的 minmaxaverage 计算得出的。可以使用特殊的 first 函数来代替其他函数,从而跳过词条枚举,仅返回第一个词条的解码有效负载。

指定的字段必须具有浮点或整数有效负载编码功能(通过 DelimitedPayloadTokenFilterNumericPayloadTokenFilter)。如果未找到词条的有效负载,则返回默认值。

  • payload(field_name,term):默认值为 0.0,使用 average 函数。

  • payload(field_name,term,default_value):默认值可以是常量、字段名称或另一个返回浮点值的函数。使用 average 函数。

  • payload(field_name,term,default_value,function):函数值可以是 minmaxaveragefirst

语法示例

  • 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 是任何任意复杂的函数。

ab 相等且 x>=0 时,此函数的最大值为 1,并且随着 x 的增加而下降。同时增加 ab 的值会导致整个函数移动到曲线的较平坦部分。当 x 为 rord(datefield) 时,这些属性可以使此函数成为提升较新文档的理想函数。

语法示例

  • recip(myfield,m,a,b)

  • recip(rord (creationDate), 1,1000,1000)

rord 函数

返回由 ord 返回的反向排序。

语法示例

  • rord(myDateField)

scale 函数

缩放函数 x 的值,使其落在指定的 minTargetmaxTarget (包括)之间。当前实现会遍历所有函数值以获取最小值和最大值,因此它可以选择正确的比例。

当前实现无法区分文档何时被删除或没有值的文档。对于这些情况,它使用 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, 距离度量)。

距离度量的可能值是

  • 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): 如果 value1value2 为 true,则为 true

xor 函数

逻辑异或,即一个或另一个,但不能同时为真。

语法示例

  • 如果 field1field2 为 true,则 xor(field1,field2) 返回 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

比较函数

gtgteltlteeq

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 的盒子,但根据盒子的体积进行排序。查询参数将是

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>