Solr查询:分析组件

Solr查询:分析组件

分析组件允许用户在结果集上计算复杂的统计聚合。

警告: 分析组件已被弃用。我们建议查看JSON分面API中的类似功能。如果JSON分面目前还没有涵盖您需要的功能,请通知项目组。

该组件使用户能够以各种方式与数据交互,通过多样化的分析函数集合以及强大的分面功能。
标准分面在分析组件中得到支持,并增加了利用其分析能力的功能。

模块

这通过需要在使用前启用的analytics Solr模块提供。

分析配置

由于分析框架是一个_搜索组件_,它必须声明为搜索组件并添加到搜索处理程序中。

对于在云集合上的分布式分析请求,该组件严格使用AnalyticsHandler进行分片间通信。
用户不应使用Analytics Handler提交分析请求。

接下来您需要注册请求处理程序和搜索组件。
将以下行添加到solrconfig.xml中,接近其他请求处理程序的定义:

1
2
3
4
5
6
7
8
9
10
11
<!-- 处理用户请求 -->
<searchComponent name="analytics" class="org.apache.solr.handler.component.AnalyticsComponent" />

<requestHandler name="/select" class="solr.SearchHandler">
<arr name="last-components">
<str>analytics</str>
</arr>
</requestHandler>

<!-- 用于分布式请求期间的分片间通信 -->
<requestHandler name="/analytics" class="org.apache.solr.handler.AnalyticsHandler" />

要使这些更改生效,请重启Solr或重新加载核心或集合。

请求语法

分析请求通过analytics参数传递给发送到搜索处理程序的请求。
由于分析请求在搜索处理程序请求内部发送,它将基于搜索处理程序确定的结果集计算结果。

例如,此curl命令编码并POST一个简单的分析请求到搜索处理程序:

1
2
3
4
5
6
$ curl --data-binary 'analytics={
"expressions" : {
"revenue" : "sum(mult(price,quantity))"
}
}'
http://localhost:8983/solr/sales/select?q=*:*&wt=json&rows=0

任何分析请求有3个主要部分:

表达式:
在整个结果集上执行的计算列表。
表达式将搜索结果聚合为要返回的单个值。
此列表完全独立于每个分组中定义的表达式。
在<<表达式>>部分了解更多信息。

函数:
一个或多个在请求的其余部分中使用的变量函数。
这些本质上是lambda函数,可以以多种方式组合。
这些函数用于在expressions以及groupings中定义的表达式。

分组:
除了表达式之外要计算的分组列表。
分组包含一组分面和要在这些分面上计算的表达式列表。
分组中定义的表达式仅在该分组中定义的分面上计算。

可选参数

请求中必须存在expressionsgroupings参数之一,否则没有要计算的分析。
functions参数始终是可选的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
"functions": {
"sale()": "mult(price,quantity)"
},
"expressions" : {
"max_sale" : "max(sale())",
"med_sale" : "median(sale())"
},
"groupings" : {
"sales" : {
"expressions" : {
"stddev_sale" : "stddev(sale())",
"min_price" : "min(price)",
"max_quantity" : "max(quantity)"
},
"facets" : {
"category" : {
"type" : "value",
"expression" : "fill_missing(category, 'No Category')",
"sort" : {
"criteria" : [
{
"type" : "expression",
"expression" : "min_price",
"direction" : "ascending"
},
{
"type" : "facetvalue",
"direction" : "descending"
}
],
"limit" : 10
}
},
"temps" : {
"type" : "query",
"queries" : {
"hot" : "temp:[90 TO *]",
"cold" : "temp:[* TO 50]"
}
}
}
}
}
}

表达式

表达式是从分析组件请求信息的方式。
这些是您希望计算并在响应中返回的统计表达式。

构建表达式

表达式组件

表达式使用字段、常量、映射函数和减少函数构建。
这些可以定义的方式如下所述。

源:

  • 常量:在表达式中定义的值。
    支持的常量类型在常量部分中描述。

  • 字段:从索引读取的Solr字段。
    支持的字段在支持的字段类型部分中列出。

映射函数:
映射函数为每个Solr文档或减少操作映射值。
提供的映射函数在分析映射函数中详细说明。

  • 未减少的映射:将字段与另一个字段或常量映射,为每个Solr文档返回一个值。
    未减少的映射函数可以将字段、常量以及其他未减少的映射函数作为输入。

  • 减少的映射:将减少函数与另一个减少函数或常量映射,返回单个值。

减少函数:
将源和/或未减少的映射函数的值为每个Solr文档减少为单个值的函数。
提供的减少函数在分析减少函数中详细说明。

组件顺序

表达式组件必须按以下顺序使用以创建有效表达式。

  1. 减少的映射函数
    1. 常量
    2. 减少函数
      1. 未减少的映射函数
        1. 未减少的映射函数
    3. 减少的映射函数
  2. 减少函数

此顺序基于以下规则:

  • 没有减少函数可以是另一个减少函数的参数。
    由于所有减少都在一个步骤中完成,一个减少函数不能依赖于另一个的结果。
  • 没有字段可以保持未减少,因为分析组件不能为表达式返回值列表(每个文档一个)。
    每个表达式都必须减少为单个值。
  • 创建函数时映射函数不是必需的,但是可以使用任意多的嵌套映射。
  • 嵌套映射函数必须是相同类型,因此要么都必须是未减少的,要么都必须是减少的。
    减少的映射函数不能将未减少的映射函数作为参数,反之亦然。

示例构建

使用上述定义和顺序,可以将示例表达式分解为其组件:

1
div(sum(a,fill_missing(b,0)),add(10.5,count(mult(a,c))))

作为整体,这是一个减少的映射函数。
div函数是减少的映射函数,因为它是提供的映射函数并且具有减少的参数。

如果我们进一步分解表达式:

  • sum(a,fill_missing(b,0)):减少函数
    sum是提供的减少函数。

    • a:字段
    • fill_missing(b,0):未减少的映射函数
      fill_missing是未减少的映射函数,因为它是提供的映射函数并且具有字段参数。
      • b:字段
      • 0:常量
  • add(10.5,count(mult(a,c))):减少的映射函数
    add是减少的映射函数,因为它是提供的映射函数并且具有减少函数参数。

    • 10.5:常量
    • count(mult(a,c)):减少函数
      count是提供的减少函数。
      • mult(a,c):未减少的映射函数
        mult是未减少的映射函数,因为它是提供的映射函数并且具有两个字段参数。
        • a:字段
        • c:字段

表达式基数(多值和单值)

所有多值表达式的根是多值字段。
单值表达式可以从常量或单值字段开始。
所有单值表达式都可以被视为包含一个值的多值表达式。

单值表达式和多值表达式可以在许多映射函数中一起使用,以及单独使用的多值表达式和一起使用的许多单值表达式。
例如:

add(<单值双精度>, <单值双精度>, ...)
返回一个单值双精度表达式,其中每个表达式的值相加。

add(<单值双精度>, <多值双精度>)
返回一个多值双精度表达式,其中第二个表达式的每个值都加到第一个表达式的单个值上。

add(<多值双精度>, <单值双精度>)
作用与上述函数相同。

add(<多值双精度>)
返回一个单值双精度表达式,它是参数表达式的多个值的总和。

类型和隐式转换

新的分析组件当前支持下表中列出的类型。
这些类型为以下关系启用了单向隐式转换:

类型 隐式转换为
Boolean String
Date Long, String
Integer Long, Float, Double, String
Long Double, String
Float Double, String
Double String
String

隐式转换意味着如果函数要求某种类型的值作为参数,参数将自动转换为该类型(如果可能)。

例如,concat()只接受字符串参数,由于所有类型都可以隐式转换为字符串,因此任何类型都作为参数被接受。

这也适用于动态类型函数。
fill_missing()需要两个相同类型的参数。
但是,隐式转换为相同类型的两种类型也可以使用。

例如,fill_missing(<长整数>,<浮点数>)将被转换为fill_missing(<双精度>,<双精度>),因为长整数不能转换为浮点数,浮点数不能隐式转换为长整数。

隐式转换有一个顺序,其中更专门的类型排在更一般的类型之前。
因此,尽管长整数和浮点数都可以隐式转换为双精度和字符串,但它们将被转换为双精度。
这是因为双精度是比字符串更专门的类型,每种类型都可以转换为字符串。

顺序与上表中的顺序相同。

基数也可以隐式转换。
单值表达式总是可以隐式转换为多值表达式,因为所有单值表达式都是具有一个值的多值表达式。

隐式转换只在表达式没有它就不会”编译”时发生。
如果表达式最初遵循所有类型规则,则不会发生隐式转换。
诸如string()date()round()floor()ceil()等函数充当显式转换,声明所需的类型。
但是round()floor()ceil()可以返回int或long,具体取决于参数类型。

变量函数

变量函数是缩短表达式并使编写分析查询更容易的方法。
它们本质上是在请求中定义的lambda函数。

1
2
3
4
5
6
7
8
9
{
"functions" : {
"sale()" : "mult(price,quantity)"
},
"expressions" : {
"max_sale" : "max(sale())",
"med_sale" : "median(sale())"
}
}

在上述请求中,不是写两次mult(price,quantity),而是定义了一个函数sale()来抽象这个概念。
然后在多个表达式中使用该函数。

假设我们想要查看特定类别的销售:

1
2
3
4
5
6
7
8
9
10
11
12
{
"functions" : {
"clothing_sale()" : "filter(mult(price,quantity),equal(category,'Clothing'))",
"kitchen_sale()" : "filter(mult(price,quantity),equal(category,\"Kitchen\"))"
},
"expressions" : {
"max_clothing_sale" : "max(clothing_sale())",
"med_clothing_sale" : "median(clothing_sale())",
"max_kitchen_sale" : "max(kitchen_sale())",
"med_kitchen_sale" : "median(kitchen_sale())"
}
}

参数

与其为每个类别制作一个函数,将category用作sale()函数的输入会更容易。
此功能的示例如下所示:

1
2
3
4
5
6
7
8
9
10
11
{
"functions" : {
"sale(cat)" : "filter(mult(price,quantity),equal(category,cat))"
},
"expressions" : {
"max_clothing_sale" : "max(sale(\"Clothing\"))",
"med_clothing_sale" : "median(sale('Clothing'))",
"max_kitchen_sale" : "max(sale(\"Kitchen\"))",
"med_kitchen_sale" : "median(sale('Kitchen'))"
}
}

变量函数可以接受任意数量的参数,并在函数表达式中将它们用作字段或常量。

变长参数

有些分析函数接受可变数量的参数。
因此有些用例需要变量函数接受可变数量的参数。

例如,产品的价格可能有多个但未确定数量的组件。
如果最后一个参数后跟..,则函数可以接受可变长度的参数

1
2
3
4
5
6
7
8
9
10
11
{
"functions" : {
"sale(cat, costs..)" : "filter(mult(add(costs),quantity),equal(category,cat))"
},
"expressions" : {
"max_clothing_sale" : "max(sale('Clothing', material, tariff, tax))",
"med_clothing_sale" : "median(sale('Clothing', material, tariff, tax))",
"max_kitchen_sale" : "max(sale('Kitchen', material, construction))",
"med_kitchen_sale" : "median(sale('Kitchen', material, construction))"
}
}

在上述示例中,变长参数用于封装用于产品的所有成本。
变长参数没有确定的参数数量请求,因此服装表达式可以使用3个,厨房表达式可以使用2个。
当调用sale()函数时,costs扩展为给定的参数。

因此在上述请求中,在sale函数内部:

  • add(costs)

扩展为以下两个:

  • add(material, tariff, tax)
  • add(material, construction)

For-Each函数

注意:高级功能

虽然上述功能允许将未定义数量的参数传递给函数,但它不允许与这些参数交互。

很多时候我们可能想要在每个参数上包装附加函数。
例如,也许我们想要同时查看多个类别。
所以我们想要看到category EQUALS x *OR* category EQUALS y等等。

为了做到这一点,我们需要使用for-each lambda函数,它转换变长参数的每个值。
for-each在变长参数后用:字符开始。

1
2
3
4
5
6
7
8
9
10
11
{
"functions" : {
"sale(cats..)" : "filter(mult(price,quantity),or(cats:equal(category,_)))"
},
"expressions" : {
"max_sale_1" : "max(sale('Clothing', 'Kitchen'))",
"med_sale_1" : "median(sale('Clothing', 'Kitchen'))",
"max_sale_2" : "max(sale('Electronics', 'Entertainment', 'Travel'))",
"med_sale_2" : "median(sale('Electronics', 'Entertainment', 'Travel'))"
}
}

在这个例子中,cats:是在每个cats参数上开始for-each lambda函数的语法,_字符用于在for-each的每次迭代中引用cats的值。
当调用sale("Clothing", "Kitchen")时,lambda函数equal(category,_)or()函数内部应用于Clothing和Kitchen。

使用所有这些规则,表达式:

1
sale("Clothing","Kitchen")

扩展为:

1
filter(mult(price,quantity),or(equal(category,"Kitchen"),equal(category,"Clothing")))

由表达式解析器处理。

分组和分面

分面,就像在Solr的其他部分一样,允许将分析结果按表达式计算的数据的属性进行分解和分组。

分析组件当前可用的分面有值分面、透视分面、范围分面和查询分面。
每个分面都需要在定义的分组中有唯一的名称,并且没有分面可以在分组之外定义。

分组允许用户在一组分面上计算相同的表达式分组。
分组必须同时给出expressionsfacets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"functions" : {
"sale()" : "mult(price,quantity)"
},
"groupings" : {
"sales_numbers" : {
"expressions" : {
"max_sale" : "max(sale())",
"med_sale" : "median(sale())"
},
"facets" : {
"<name>" : "< facet request >"
}
}
}
}
1
2
3
4
5
6
7
8
9
{
"analytics_response" : {
"groupings" : {
"sales_numbers" : {
"<name>" : "< facet response >"
}
}
}
}

分面排序

一些分析分面允许对其结果进行复杂排序。
当前的两个可排序分面是分析值分面和分析透视分面。

参数

criteria:
排序分面的标准列表。

它接受以下参数:

type:
排序类型。有两个可能的值:

  • expression:按同一分组中定义的表达式的值排序。
  • facetvalue:按分面值的字符串表示排序。

Direction:
排序方向。选项是ascendingdescending

expression:
typeexpression时,是同一分组中定义的表达式的名称。

limit:
将返回的分面值数量限制为前N个。默认值意味着没有限制。

offset:
当设置限制时,跳过前N个分面值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"criteria" : [
{
"type" : "expression",
"expression" : "max_sale",
"direction" : "ascending"
},
{
"type" : "facetvalue",
"direction" : "descending"
}
],
"limit" : 10,
"offset" : 5
}

值分面

值分面用于按应用于每个文档的映射表达式的值对文档进行分组。
映射表达式是不包含减少函数的表达式。

有关更多信息,请参考表达式部分。
例如:

  • mult(quantity, sum(price, tax)):按产生的收入分解文档。
  • fillmissing(state, "N/A"):按州分解文档,当文档不包含州时使用N/A。

值分面可以排序。

参数

expression:
为每个文档选择分面存储桶的表达式。

sort:
透视结果的排序。

1
2
3
4
5
{
"type" : "value",
"expression" : "fillmissing(category,'No Category')",
"sort" : {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
{ "..." : "..." },
{
"value" : "Electronics",
"results" : {
"max_sale" : 103.75,
"med_sale" : 15.5
}
},
{
"value" : "Kitchen",
"results" : {
"max_sale" : 88.25,
"med_sale" : 11.37
}
},
{ "..." : "..." }
]

注意: 这是原始分析组件中存在的字段分面的替代。
通过使用字段名称作为表达式,值分面中保持了字段分面功能。

分析透视分面

透视分面用于按应用于每个文档的多个映射表达式的值对文档进行分组。

透视分面的工作很像值分面的层。
需要透视列表,列表的顺序直接影响返回的结果。
给出的第一个透视将被视为正常值分面。
给出的第二个透视将被视为第一个透视每个值的一个值分面。
这些第二级值分面中的每一个都将限制于其第一级分面存储桶中的文档。
无论提供多少透视,这都会继续。

排序在每个透视基础上启用。
这意味着如果您的顶部透视有一个limit:1的排序,那么只有分面的第一个值将被钻取。
每个透视中的排序独立于其他透视。

参数

pivots:
要计算钻取分面的透视列表。
列表按从最顶层到最底层的顺序排序。

name:
透视的名称。

expression:
为每个文档选择分面存储桶的表达式。

sort:
透视结果的排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"type" : "pivot",
"pivots" : [
{
"name" : "country",
"expression" : "country",
"sort" : {}
},
{
"name" : "state",
"expression" : "fillmissing(state, fillmissing(providence, territory))"
},
{
"name" : "city",
"expression" : "fillmissing(city, 'N/A')",
"sort" : {}
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[
{ "..." : "..." },
{
"pivot" : "Country",
"value" : "USA",
"results" : {
"max_sale" : 103.75,
"med_sale" : 15.5
},
"children" : [
{ "..." : "..." },
{
"pivot" : "State",
"value" : "Texas",
"results" : {
"max_sale" : 99.2,
"med_sale" : 20.35
},
"children" : [
{ "..." : "..." },
{
"pivot" : "City",
"value" : "Austin",
"results" : {
"max_sale" : 94.34,
"med_sale" : 17.60
}
},
{ "..." : "..." }
]
},
{ "..." : "..." }
]
},
{ "..." : "..." }
]

分析范围分面

范围分面用于将文档按字段的值分组到给定的范围集合中。
分析范围分面的输入与Solr范围分面使用的输入相同。
有关使用的更多信息,请参考范围分面部分。

参数

field:
要进行分面的字段。

start:
范围的底端。

end:
范围的顶端。

gap:
用于生成分面存储桶的范围间隙列表。
如果存储桶不能加起来适合从startend的范围,那么最后的gap值将重复所需的次数以填充任何未使用的范围。

hardend:
如果最后一个分面存储桶范围在end值处溢出,是否在end值处切断它。

include:
要包含在分面存储桶中的边界。

  • lower - 所有基于间隙的范围包括其下边界。
  • upper - 所有基于间隙的范围包括其上边界。
  • edge - 第一个和最后一个间隙范围包括其边界(第一个的下边界,最后一个的上边界),即使没有指定相应的上/下选项。
  • outer - beforeafter范围将包含其边界,即使第一个或最后一个范围已经包含这些边界。
  • all - 包括所有选项:lowerupperedgeouter

others:
要包含在分面中的附加范围。

  • before - 所有字段值低于第一个范围下边界的记录。
  • after - 所有字段值大于最后一个范围上边界的记录。
  • between - 所有字段值在第一个范围下边界和最后一个范围上边界之间的记录。
  • none - 不包括上述任何分面存储桶。
  • all - 包括beforeafterbetween的分面存储桶。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"type" : "range",
"field" : "price",
"start" : "0",
"end" : "100",
"gap" : [
"5",
"10",
"10",
"25"
],
"hardend" : true,
"include" : [
"lower",
"upper"
],
"others" : [
"after",
"between"
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[
{
"value" : "[0 TO 5]",
"results" : {
"max_sale" : 4.75,
"med_sale" : 3.45
}
},
{
"value" : "[5 TO 15]",
"results" : {
"max_sale" : 13.25,
"med_sale" : 10.20
}
},
{
"value" : "[15 TO 25]",
"results" : {
"max_sale" : 22.75,
"med_sale" : 18.50
}
},
{
"value" : "[25 TO 50]",
"results" : {
"max_sale" : 47.55,
"med_sale" : 30.33
}
},
{
"value" : "[50 TO 75]",
"results" : {
"max_sale" : 70.25,
"med_sale" : 64.54
}
},
{ "..." : "..." }
]

查询分面

查询分面用于按给定的查询集合对文档进行分组。

参数

queries:
要进行分面的查询列表。

1
2
3
4
5
6
7
{
"type" : "query",
"queries" : {
"high_quantity" : "quantity:[ 5 TO 14 ] AND price:[ 100 TO * ]",
"low_quantity" : "quantity:[ 1 TO 4 ] AND price:[ 100 TO * ]"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[
{
"value" : "high_quantity",
"results" : {
"max_sale" : 4.75,
"med_sale" : 3.45
}
},
{
"value" : "low_quantity",
"results" : {
"max_sale" : 13.25,
"med_sale" : 10.20
}
}
]
© 2025 Solr Community of China All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero