使用 Solr 的分层分面搜索示例

Hierarchical faceted search example with Solr

问题

我在哪里可以找到一个完整的示例来说明分层分面搜索是如何从索引文档到检索搜索结果的?

我目前的研究

Whosebug 有一些帖子,但它们都只解决了层次分面搜索的某些方面;因此,我不会认为它们是重复的。我正在寻找一个完整的例子来理解它。我总是错过聚合起作用的最后一个查询。

Solr 网页上有文档,但不理解那里给出的示例。

示例(概念上)

我想在这里创建一个完整的演练示例,希望您能提供缺少的最后一部分。

测试数据

输入

假设我们有 3 个文档,每个文档都是一个人。

Alice (document 1)
 - Blond
 - Europe

Jane (document 2)
 - Brown
 - Europe/Norway

Bob (document 3)
 - Brown
 - Europe/Norway
 - Europe/Sweden

输出

此(当前错误)查询的预期输出

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true&facet=true&facet.field=tags_ss

应该是

Hair_color (3)
- blond (1)
- brown (1)
- black (1)

Location (3)
- Europe (4)  // This should be 4 not 3, i.e. the sum of the leaves, because Alice is tagged with "Europe" only, without a country
  - Norway (2)
  - Sweden (1)

因为所有文档都找到了。

示例(以编程方式)

这是我需要帮助的地方。我如何实现上述概念示例?

这是我的进度。

1.创建测试数据XML

这是 solr-5.1.0/testdata 子文件夹中 documents.xml 文件的内容:

<add>
    <doc>
        <field name="id">Alice</field>
        <field name="tags_ss">hair_color/blond</field>
        <field name="tags_ss">location/Europe</field>
    </doc>
    <doc>
        <field name="id">Jane</field>
        <field name="tags_ss">hair_color/brown</field>
        <field name="tags_ss">location/Europe/Norway</field>
    </doc>
    <doc>
        <field name="id">Bob</field>
        <field name="tags_ss">hair_color/black</field>
        <field name="tags_ss">location/Europe/Norway</field>
        <field name="tags_ss">location/Europe/Sweden</field>
    </doc>
</add>

_ssschema.xml中定义为

<dynamicField name="*_ss" type="string"  indexed="true"  stored="true" multiValued="true"/>

请注意所有标签,例如hair_color location 以及将来添加的任何标签都存储在相同的 tags_ss 字段中。

2。使用 Solr

索引测试数据
c:\solr-5.1.0>java -classpath dist/solr-core-5.1.0.jar -Dauto=yes -Dc=gettingstarted -Ddata=files -Drecursive=yes -Durl=http://server:8983/solr/my_core/update org.apache.solr.util.SimplePostTool .\testdata

3。使用 Solr 查询检索所有数据(没有分面)

查询

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true

结果

{
  "responseHeader": {
    "status": 0,
    "QTime": 0,
    "params": {
      "indent": "true",
      "q": "*:*",
      "_": "1430830360536",
      "wt": "json"
    }
  },
  "response": {
    "numFound": 3,
    "start": 0,
    "docs": [
      {
        "id": "Alice",
        "tags_ss": [
          "hair_color/blond",
          "location/europe"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Jane",
        "tags_ss": [
          "hair_color/brown",
          "location/europe/Norway"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Bob",
        "tags_ss": [
          "hair_color/black",
          "location/europe/Norway",
          "location/europe/Sweden"
        ],
        "_version_": 1500334369469890600
      }
    ]
  }
}

4.使用 Solr 查询检索所有数据(with faceting)

查询

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true&facet=true&facet.field=tags_ss

结果

{
  "responseHeader": {
    "status": 0,
    "QTime": 0,
    "params": {
      "facet": "true",
      "indent": "true",
      "q": "*:*",
      "_": "1430830432389",
      "facet.field": "tags_ss",
      "wt": "json"
    }
  },
  "response": {
    "numFound": 3,
    "start": 0,
    "docs": [
      {
        "id": "Alice",
        "tags_ss": [
          "hair_color/blond",
          "location/europe"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Jane",
        "tags_ss": [
          "hair_color/brown",
          "location/europe/Norway"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Bob",
        "tags_ss": [
          "hair_color/black",
          "location/europe/Norway",
          "location/europe/Sweden"
        ],
        "_version_": 1500334369469890600
      }
    ]
  },
  "facet_counts": {
    "facet_queries": {},
    "facet_fields": {
      "tags_ss": [
        "location/europe/Norway",
        2,
        "hair_color/black",
        1,
        "hair_color/blond",
        1,
        "hair_color/brown",
        1,
        "location/europe",
        1,
        "location/europe/Sweden",
        1
      ]
    },
    "facet_dates": {},
    "facet_ranges": {},
    "facet_intervals": {},
    "facet_heatmaps": {}
  }
}

注意结果底部的这一部分:

"facet_fields": {
  "tags_ss": [
    "location/europe/Norway",
    2,
    "hair_color/black",
    1,
    "hair_color/blond",
    1,
    "hair_color/brown",
    1,
    "location/europe",
    1,
    "location/europe/Sweden",
    1
  ]
},

它将所有标签显示为平面列表(不分层)。

5.使用 Solr 查询检索所有数据(使用 hierarchical faceting)

查询

这是我的问题。我不知道如何构造 returns 以下结果的查询(结果已在上面的概念示例中显示)。

结果(虚构,为说明而手工创建)

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "facet":"true",
      "indent":"true",
      "q":"*:*",
      "facet.field":"tags_ss",
      "wt":"json",
      "rows":"0"}},
  "response":{"numFound":3,"start":0,"docs":[]
  },
  "facet_counts":{
    "facet_queries":{},
    "facet_fields":{
      "tags_ss":[
        "hair_color,3, // This aggregations is missing
        "hair_color/black",1,
        "hair_color/blond",1,
        "hair_color/brown",1,
        "location/europe",4, // This aggregation should be 4 but is 1
        "location/europe/Norway",2,
        "location/europe/Sweden",1]},
    "facet_dates":{},
    "facet_ranges":{},
    "facet_intervals":{},
    "facet_heatmaps":{}}}

这个标签列表仍然是扁平的,但至少 location/europe = 4 会被正确聚合,但目前不是。我一直收到 location/europe = 1,因为它仅针对 Alice 设置,而 BobNorwaySweden 未汇总到 Europe

想法

版本

如果您分阶段将它们推入索引,则可以填充所有聚合。如果 Bob 来自挪威,您最多可以在 facet 字段中填充三个值:

location
location/Europe
location/Europe/Norway

(作为替代设计,您可能有一个与位置字段分开的头发颜色字段,然后 "location" 永远不需要在该字段本身中填充。)

那么你的结果仍然持平,但你的总计是存在的。届时,您将需要对结果集进行一些编程工作,以创建一个嵌套数据结构,该结构是通过拆分分隔符(本例中为 /)上的所有值而构建的。一旦你有了嵌套的数据结构,那么分层显示它应该是易于管理的。很难详细介绍这部分实现,因为您的嵌套数据结构和显示将在很大程度上取决于您的开发环境。

避免在 Solr 构面字段中添加重复条目的另一个有点冒险的选项是仅添加您现在使用的值(例如 location/Europe/Norway),但将叶总数作为迭代求和通过构面列表并构建您的嵌套数据结构。存在的风险是,如果一个人真正与欧洲的多个国家有联系,那么您可能会得到更高级别的夸大总数 location/Europe。如上所述,我在自己的项目中选择了填充单独的值。尽管它们看起来多余,但总计最终会更准确。

(与 Solr 中的往常一样,这只是许多做事方式中的一种。此模型最适用于总叶数可管理的系统,在这种情况下检索所有方面值是有意义的前面,而不必进行额外的向下钻取查询。)

一个旋转选项

Solr facet pivoting 可以 return 直接从 Solr 获得层次结构的结果,但在某些情况下存在在值之间创建错误连接的风险。

所以,假设您像这样加载文档:

<add>
 <doc>
  <field name="id">Alice</field>
  <field name="continent">Europe</field>
 </doc>
 <doc>
  <field name="id">Jane</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
 </doc>
 <doc>
  <field name="id">Bob</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
  <field name="country">Sweden</field>
 </doc>
</add>

现在您使用 facet.pivot.mincount=1&facet.pivot=continent,country 执行分面数据透视查询。到目前为止,结果可能很棒:

"facet_pivot":{
 "continent,country":[{
  "field":"continent",
  "value":"Europe",
  "count":3,
  "pivot":[{
    "field":"country",
    "value":"Norway",
    "count":2,},
      {
    "field":"country",
    "value":"Sweden",
    "count":1,}]}]}

到目前为止一切顺利。当您向数据中添加一个新人时,问题就来了:

<add>
 <doc>
  <field name="id">Susan</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
  <field name="continent">South America</field
  <field name="country">Brazil</field>
 </doc>
</add>

现在 Solr 实际上并不知道挪威在欧洲而巴西在南美洲,因此您将开始获得 "Europe > Brazil" 和 "South America > Norway".[=19= 的分面数]

如果您为所有国家/地区值添加大洲前缀,则问题可以解决:

<add>
 <doc>
  <field name="id">Susan</field>
  <field name="continent">Europe</field>
  <field name="country">Europe/Norway</field>
  <field name="continent">South America</field
  <field name="country">South America/Brazil</field>
 </doc>
</add>

这样您仍然会得到不匹配的主元值,但您可以选择阻止任何没有与其大陆相匹配的前缀的国家级方面值。要使这成为一个问题,数据透视表中的 多值 字段必须具有与同一数据透视表中 之后 出现的值关联的值。如果您不希望单个记录中的这些字段有多个值,或者如果您的值没有强关联(即特定的出身),则数据透视面可能是一个理想的解决方案。但在某些情况下,透视面在包含字段中的值之间的分离可能会造成令人望而却步的混乱。