分析组件
Analytics 组件允许用户对结果集计算复杂的统计聚合。
analytics 组件已弃用。我们建议查看 JSON Facet API 中找到的类似功能。如果 JSON facet 未涵盖你需要的功能,请通知项目。 |
该组件支持通过各种方式与数据交互,既可以通过多种分析函数,也可以通过强大的分面功能。标准分面在分析组件中受支持,并增加了利用其分析功能的内容。
模块
这通过 analytics
Solr 模块 提供,在使用前需要启用。
分析配置
由于 Analytics 框架是一个搜索组件,因此必须声明为搜索组件并添加到搜索处理程序。
对于云集合上的分布式分析请求,该组件严格使用 AnalyticsHandler
进行分片间通信。用户不应使用 Analytics 处理程序提交分析请求。
接下来,你需要注册请求处理程序和搜索组件。将以下行添加到 solrconfig.xml
,靠近其他请求处理程序的定义
<!-- To handle user requests -->
<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>
<!-- For inter-shard communication during distributed requests -->
<requestHandler name="/analytics" class="org.apache.solr.handler.AnalyticsHandler" />
要使这些更改生效,请重新启动 Solr 或重新加载核心或集合。
请求语法
Analytics 请求通过参数 analytics
传递给 Solr,该参数在发送到搜索处理程序的请求中。由于 Analytics 请求是在搜索处理程序请求中发送的,因此它将根据搜索处理程序确定的结果集计算结果。
例如,此 curl 命令对一个简单的 Analytics 请求进行编码并将其 POST 到搜索处理程序
$ curl --data-binary 'analytics={
"expressions" : {
"revenue" : "sum(mult(price,quantity))"
}
}'
http://localhost:8983/solr/sales/select?q=*:*&wt=json&rows=0
任何 Analytics 请求都有 3 个主要部分
可选参数 请求中必须存在 expressions 或 groupings 参数,否则将没有要计算的 Analytics。functions 参数始终是可选的。 |
{
"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]"
}
}
}
}
}
}
表达式
表达式是从 Analytics 组件请求信息片段的方法。这些是您希望在响应中计算并返回的统计表达式。
构造表达式
组件排序
必须按以下顺序使用表达式组件才能创建有效的表达式。
-
归约映射函数
-
常量
-
归约函数
-
源
-
未归约映射函数
-
源
-
未归约映射函数
-
-
-
归约映射函数
-
-
归约函数
此排序基于以下规则
-
没有归约函数可以成为另一个归约函数的参数。由于所有归约都在一步中完成,因此一个归约函数不能依赖于另一个归约函数的结果。
-
没有字段可以保持未归约,因为分析组件无法返回表达式的值列表(每个文档一个)。每个表达式都必须归约为单个值。
-
创建函数时不需要映射函数,但是可以使用尽可能多的嵌套映射。
-
嵌套映射函数必须是同类型的,因此两者都必须未归约或都必须归约。归约映射函数不能将未归约映射函数作为参数,反之亦然。
示例构建
根据以上定义和排序,可以将示例表达式分解为其组件
div(sum(a,fill_missing(b,0)),add(10.5,count(mult(a,c)))))
作为一个整体,这是一个约简映射函数。div
函数是一个约简映射函数,因为它是一个提供的映射函数,并且具有约简参数。
如果我们进一步分解表达式
表达式基数(多值和单值)
所有多值表达式的根源都是多值字段。单值表达式可以从常量或单值字段开始。所有单值表达式都可以视为包含一个值的多值表达式。
单值表达式和多值表达式可以在许多映射函数中一起使用,以及仅使用多值表达式,以及一起使用许多单值表达式。例如
add(<单值双精度>,<单值双精度>,…)
-
返回一个单值双精度表达式,其中每个表达式的值的值相加。
add(<单值双精度>,<多值双精度>)
-
返回一个多值双精度表达式,其中第二个表达式的每个值都添加到第一个表达式的单值。
add(<多值双精度>,<单值双精度>)
-
与上述函数的作用相同。
add(<多值双精度>)
-
返回一个单值双精度表达式,它是参数表达式的多个值的总和。
类型和隐式转换
新的分析组件当前支持下表中列出的类型。这些类型已为以下关系启用了单向隐式转换
类型 | 隐式转换为 |
---|---|
布尔值 |
字符串 |
日期 |
长整型、字符串 |
整型 |
长整型、浮点型、双精度型、字符串 |
长整型 |
双精度型、字符串 |
浮点数 |
双精度型、字符串 |
双精度浮点数 |
字符串 |
字符串 |
无 |
隐式转换意味着如果函数需要某种类型的值作为参数,如果可能,参数将自动转换为该类型。
例如,concat()
只接受字符串参数,并且由于所有类型都可以隐式转换为字符串,因此任何类型都可以作为参数接受。
这同样适用于动态类型函数。fill_missing()
需要两个相同类型的参数。但是,也可以使用隐式转换为相同类型的两种类型。
例如,fill_missing(<long>,<float>)
将转换为 fill_missing(<double>,<double>)
,因为 long 无法隐式转换为 float,而 float 也无法隐式转换为 long。
隐式转换有一个顺序,其中更具体的类型排在更一般的类型之前。因此,即使 long 和 float 都可以隐式转换为 double 和 string,它们也将转换为 double。这是因为 double 是比 string 更具体的类型,所有类型都可以转换为 string。
顺序与上表中的顺序相同。
基数也可以隐式转换。单值表达式始终可以隐式转换为多值表达式,因为所有单值表达式都是具有一个值的多值表达式。
只有当表达式在没有隐式转换的情况下无法“编译”时,才会发生隐式转换。如果表达式最初遵循所有类型规则,则不会发生隐式转换。某些函数(如 string()
、date()
、round()
、floor()
和 ceil()
)充当显式转换,声明所需的类型。但是,round()
、floor()
和 cell()
可以根据参数类型返回 int 或 long。
变量函数
变量函数是一种缩短表达式并简化编写分析查询的方法。它们本质上是在请求中定义的 lambda 函数。
{
"functions" : {
"sale()" : "mult(price,quantity)"
},
"expressions" : {
"max_sale" : "max(sale())",
"med_sale" : "median(sale())"
}
}
在上述请求中,没有两次编写 mult(price,quantity)
,而是定义了一个函数 sale()
来抽象这个想法。然后在多个表达式中使用了该函数。
假设我们要查看特定类别的销售情况
{
"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()
函数的输入要容易得多。此功能的一个示例如下所示
{
"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'))"
}
}
变量函数可以接受任意数量的参数,并在函数表达式中使用它们,就好像它们是字段或常量一样。
可变长度参数
有一些分析函数需要可变数量的参数。因此,在某些情况下,变量函数需要接受可变数量的参数。
例如,产品的价格可能有多个尚未确定的组成部分。如果最后一个参数后跟 ..
,函数可以采用长度可变的参数
{
"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 以可变长度参数后的 :
字符开头。
{
"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。
使用所有这些规则,表达式
`sale("Clothing","Kitchen")`
会扩展为
`filter(mult(price,quantity),or(equal(category,"Kitchen"),equal(category,"Clothing")))`
通过表达式解析器。
分组和分面
与 Solr 其他部分类似,分面允许按表达式计算数据的属性对分析结果进行分解和分组。
分析组件中当前可用于的分面为值分面、透视分面、范围分面和查询分面。每个分面在其定义的分组中必须具有唯一名称,并且不能在分组外部定义任何分面。
分组允许用户对一组分面计算相同的表达式分组。分组必须同时给出 expressions
和 facets
。
{
"functions" : {
"sale()" : "mult(price,quantity)"
},
"groupings" : {
"sales_numbers" : {
"expressions" : {
"max_sale" : "max(sale())",
"med_sale" : "median(sale())"
},
"facets" : {
"<name>" : "< facet request >"
}
}
}
}
{
"analytics_response" : {
"groupings" : {
"sales_numbers" : {
"<name>" : "< facet response >"
}
}
}
}
分面排序
参数
criteria
-
必需
默认值:无
按其对分面进行排序的条件列表。
它采用以下参数
type
-
必需
默认值:无
排序类型。有两个可能值:*
expression
:按同一分组中定义的表达式的值进行排序。*facetvalue
:按分面值的字符串表示形式进行排序。 Direction
-
可选
默认值:
ascending
排序方向。选项为
ascending
或descending
。 expression
-
可选
默认值:无
当
type
为expression
时,同一分组中定义的表达式的名称。
limit
-
可选
默认值:
-1
将返回的分面值数量限制为前 N 个。默认值表示没有限制。
offset
-
可选
默认值:
0
当设置限制时,跳过前 N 个分面值。
{
"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
-
可选
默认值:无
透视结果的 排序。
{
"type" : "value",
"expression" : "fillmissing(category,'No Category')",
"sort" : {}
}
[
{ "..." : "..." },
{
"value" : "Electronics",
"results" : {
"max_sale" : 103.75,
"med_sale" : 15.5
}
},
{
"value" : "Kitchen",
"results" : {
"max_sale" : 88.25,
"med_sale" : 11.37
}
},
{ "..." : "..." }
]
这是原始 Analytics 组件中存在的字段切面的替代项。通过将字段的名称用作表达式,值切面中保留了字段切面功能。 |
分析透视切面
透视切面用于按应用于每个文档的多个映射表达式的值对文档进行分组。
透视切面与值切面的层非常相似。需要透视列表,并且列表的顺序直接影响返回的结果。给出的第一个透视将被视为普通值切面。给出的第二个透视将被视为第一个透视的每个值的单个值切面。这些第二级值切面中的每一个都将限制在其第一级切面存储桶中的文档。这将持续到提供任意多个透视。
按每个透视启用排序。这意味着,如果你的顶级透视具有排序,其中 limit:1
,那么只有该切面的第一个值将被向下钻取。每个透视中的排序独立于其他透视。
参数
透视图
-
必需
默认值:无
用于计算向下钻取切面的透视图列表。列表按从最高级别到最低级别的顺序排列。
名称
-
必需
默认值:无
透视图的名称。
expression
-
必需
默认值:无
为每个文档选择分面存储区的表达式。
sort
-
可选
默认值:无
透视结果的 排序。
{
"type" : "pivot",
"pivots" : [
{
"name" : "country",
"expression" : "country",
"sort" : {}
},
{
"name" : "state",
"expression" : "fillmissing(state, fillmissing(providence, territory))"
},
{
"name" : "city",
"expression" : "fillmissing(city, 'N/A')",
"sort" : {}
}
]
}
[
{ "..." : "..." },
{
"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 范围切面的输入相同。有关如何使用,请参阅范围切面部分。
参数
字段
-
必需
默认值:无
要按其进行切面的字段。
开始
-
必需
默认值:无
范围的底端。
结束
-
必需
默认值:无
范围的顶端。
间隙
-
必需
默认值:无
要生成切面存储桶的范围间隙列表。如果存储桶加起来不适合从
start
到end
的范围,那么最后一个gap
值将重复任意多次以填充任何未使用的范围。 硬化
-
可选
默认值:
false
如果最后一个 facet 桶范围溢出,是否将其切断在
end
值处。 include
-
可选
默认值:
lower
要包含在 facet 桶中的边界。*
lower
- 所有基于 gap 的范围都包括其下界。*upper
- 所有基于 gap 的范围都包括其上界。*edge
- 第一个和最后一个 gap 范围包括其边缘边界(第一个范围的下界,最后一个范围的上界),即使未指定相应的上界/下界选项。*outer
-before
和after
范围将包含其边界,即使第一个或最后一个范围已包含这些边界。*all
- 包含所有选项:lower
、upper
、edge
和outer
。 others
-
可选
默认值:
none
要包含在 facet 中的其他范围。*
before
- 字段值低于第一个范围下界的记录。*after
- 字段值高于最后一个范围上界的记录。*between
- 字段值介于第一个范围的下界和最后一个范围的上界之间的记录。*none
- 不为上述任何范围包含 facet 桶。*all
- 为before
、after
和between
包含 facet 桶。
{
"type" : "range",
"field" : "price",
"start" : "0",
"end" : "100",
"gap" : [
"5",
"10",
"10",
"25"
],
"hardend" : true,
"include" : [
"lower",
"upper"
],
"others" : [
"after",
"between"
]
}
[
{
"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
}
},
{ "..." : "..." }
]
查询 Facets
查询 facets 用于按给定的查询集对文档进行分组。
参数
queries
-
必需
默认值:无
要按其进行 facet 的查询列表。
{
"type" : "query",
"queries" : {
"high_quantity" : "quantity:[ 5 TO 14 ] AND price:[ 100 TO * ]",
"low_quantity" : "quantity:[ 1 TO 4 ] AND price:[ 100 TO * ]"
}
}
[
{
"value" : "high_quantity",
"results" : {
"max_sale" : 4.75,
"med_sale" : 3.45
}
},
{
"value" : "low_quantity",
"results" : {
"max_sale" : 13.25,
"med_sale" : 10.20
}
}
]