分析组件

Analytics 组件允许用户对结果集计算复杂的统计聚合。

analytics 组件已弃用。我们建议查看 JSON Facet API 中找到的类似功能。如果 JSON facet 未涵盖你需要的功能,请通知项目。

该组件支持通过各种方式与数据交互,既可以通过多种分析函数,也可以通过强大的分面功能。标准分面在分析组件中受支持,并增加了利用其分析功能的内容。

模块

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

分析配置

由于 Analytics 框架是一个搜索组件,因此必须声明为搜索组件并添加到搜索处理程序。

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

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

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 个主要部分

表达式

在整个结果集上执行的一系列计算。表达式将搜索结果汇总为要返回的单个值。此列表完全独立于每个分组中定义的表达式。在表达式部分中了解有关它们的更多信息。

函数

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

分组

分组列表,用于计算除了表达式之外的内容。分组包含一组切面和一组要针对这些切面计算的表达式。分组中定义的表达式仅针对该分组中定义的切面计算。

可选参数
请求中必须存在 expressionsgroupings 参数,否则将没有要计算的 Analytics。functions 参数始终是可选的。
Analytics 请求示例
{
    "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 组件请求信息片段的方法。这些是您希望在响应中计算并返回的统计表达式。

构造表达式

表达式组件

表达式使用字段、常量、映射函数和约简函数构建。下面描述了可以定义这些表达式的方式。

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

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

映射函数

映射函数映射每个 Solr 文档或归约的值。提供的映射函数在 分析映射函数 中进行了详细说明。

  • 未归约映射:使用另一个字段或常量映射字段会返回每个 Solr 文档的值。未归约映射函数可以将字段、常量以及其他未归约映射函数作为输入。

  • 归约映射:使用另一个归约函数或常量映射归约函数会返回单个值。

归约函数

将源的值和/或每个 Solr 文档的未归约映射函数归约为单个值的函数。提供的归约函数在 分析归约函数 中进行了详细说明。

组件排序

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

  1. 归约映射函数

    1. 常量

    2. 归约函数

      1. 未归约映射函数

        1. 未归约映射函数

    3. 归约映射函数

  2. 归约函数

此排序基于以下规则

  • 没有归约函数可以成为另一个归约函数的参数。由于所有归约都在一步中完成,因此一个归约函数不能依赖于另一个归约函数的结果。

  • 没有字段可以保持未归约,因为分析组件无法返回表达式的值列表(每个文档一个)。每个表达式都必须归约为单个值。

  • 创建函数时不需要映射函数,但是可以使用尽可能多的嵌套映射。

  • 嵌套映射函数必须是同类型的,因此两者都必须未归约或都必须归约。归约映射函数不能将未归约映射函数作为参数,反之亦然。

示例构建

根据以上定义和排序,可以将示例表达式分解为其组件

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(<多值双精度>)

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

类型和隐式转换

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

类型 隐式转换为

布尔值

字符串

日期

长整型、字符串

整型

长整型、浮点型、双精度型、字符串

长整型

双精度型、字符串

浮点数

双精度型、字符串

双精度浮点数

字符串

字符串

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

例如,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 以可变长度参数后的 : 字符开头。

带 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 其他部分类似,分面允许按表达式计算数据的属性对分析结果进行分解和分组。

分析组件中当前可用于的分面为值分面、透视分面、范围分面和查询分面。每个分面在其定义的分组中必须具有唯一名称,并且不能在分组外部定义任何分面。

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

基本分面请求示例
{
    "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

排序方向。选项为 ascendingdescending

expression

可选

默认值:无

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

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 范围切面的输入相同。有关如何使用,请参阅范围切面部分。

参数

字段

必需

默认值:无

要按其进行切面的字段。

开始

必需

默认值:无

范围的底端。

结束

必需

默认值:无

范围的顶端。

间隙

必需

默认值:无

要生成切面存储桶的范围间隙列表。如果存储桶加起来不适合从 startend 的范围,那么最后一个 gap 值将重复任意多次以填充任何未使用的范围。

硬化

可选

默认值:false

如果最后一个 facet 桶范围溢出,是否将其切断在 end 值处。

include

可选

默认值:lower

要包含在 facet 桶中的边界。* lower - 所有基于 gap 的范围都包括其下界。* upper - 所有基于 gap 的范围都包括其上界。* edge - 第一个和最后一个 gap 范围包括其边缘边界(第一个范围的下界,最后一个范围的上界),即使未指定相应的上界/下界选项。* outer - beforeafter 范围将包含其边界,即使第一个或最后一个范围已包含这些边界。* all - 包含所有选项:lowerupperedgeouter

others

可选

默认值:none

要包含在 facet 中的其他范围。* before - 字段值低于第一个范围下界的记录。* after - 字段值高于最后一个范围上界的记录。* between - 字段值介于第一个范围的下界和最后一个范围的上界之间的记录。* none - 不为上述任何范围包含 facet 桶。* all - 为 beforeafterbetween 包含 facet 桶。

示例范围 facet 请求
{
    "type" : "range",
    "field" : "price",
    "start" : "0",
    "end" : "100",
    "gap" : [
        "5",
        "10",
        "10",
        "25"
    ],
    "hardend" : true,
    "include" : [
        "lower",
        "upper"
    ],
    "others" : [
        "after",
        "between"
    ]
}
示例范围 facet 响应
[
    {
        "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 的查询列表。

示例查询 facet 请求
{
    "type" : "query",
    "queries" : {
        "high_quantity" : "quantity:[ 5 TO 14 ] AND price:[ 100 TO * ]",
        "low_quantity" : "quantity:[ 1 TO 4 ] AND price:[ 100 TO * ]"
    }
}
示例查询 facet 响应
[
    {
        "value" : "high_quantity",
        "results" : {
            "max_sale" : 4.75,
            "med_sale" : 3.45
        }
    },
    {
        "value" : "low_quantity",
        "results" : {
            "max_sale" : 13.25,
            "med_sale" : 10.20
        }
    }
]