JSON 分面域更改

分面计算在文档的“域”上运行。默认情况下,此域由主查询匹配的文档组成。对于子分面,域由父分面将其放置在其存储桶中的所有文档组成。

用户还可以使用显式的 domain 属性来覆盖划分数据的分面的“域”,该属性的值是一个 JSON 对象,该对象可以支持各种选项,用于在为相关分面计算存储桶之前限制、扩展或完全更改原始域。

domain 更改只能在执行数据划分的单个分面上指定,而不能在统计/度量分面或分面组上指定。

带有 domain 更改的 *:* 查询分面可以用于对任何类型的多个子分面进行分组,以便应用常见的域更改。

添加域过滤器

域更改的最简单示例是指定一个附加过滤器,该过滤器将应用于现有域。这可以通过分面的 domain 块中的 filter 关键字来完成。

  • curl

  • SolrJ

curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
  "query": "*:*",
  "facet": {
    "categories": {
      "type": "terms",
      "field": "cat",
      "limit": 3,
      "domain": {
        "filter": "popularity:[5 TO 10]"
      }
    }
  }
}'
final TermsFacetMap categoryFacet =
    new TermsFacetMap("cat")
        .setLimit(3)
        .withDomain(new DomainMap().withFilter("popularity:[5 TO 10]"));
final JsonQueryRequest request =
    new JsonQueryRequest().setQuery("*:*").withFacet("categories", categoryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);

filter 的值可以是单个查询(将其视为过滤器),也可以是过滤器查询的 JSON 列表。每个查询可以是

  • 一个包含 Solr 查询语法的查询字符串。

  • 对包含 Solr 查询语法的请求参数的引用,形式为:{param: <request_param_name>}。可以引用 JSON 请求 API 中 queries 键下定义的 DSL 语法中的一个或多个查询。被引用的参数可能具有 0(不存在)或多个值。

    • 当未指定值时,不应用过滤器,也不会引发错误。

    • 当指定多个值时,每个值都会被解析,并组合使用为过滤器。

以下是引用 DSL 查询的示例

curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
  "query": "*:*",
  "queries": {
      "sample_filtrs":[
           {"field":{"f":"text", "query":"usb"}},
           {"field":{"f":"text", "query":"lcd"}}
        ],
        "another_filtr":
            {"field":{"f":"text", "query":"usb"}}
  },
  "facet": {
    "usblcd": {
      "type": "terms",
      "field": "cat",
      "limit": 3,
      "domain": {
        "filter": {"param":"sample_filtrs"}
      }
    },
    "justusb": {
      "type": "terms",
      "field": "cat",
      "limit": 3,
      "domain": {
        "filter": {"param":"another_filtr"}
      }
    }
  }
}'

filter 选项与其他 domain 更改选项组合使用时,会在其他域更改发生之后应用过滤。

过滤器排除

还可以使用 excludeTags 关键字来丢弃或忽略特定的标记查询过滤器,从而扩展域。

以下示例使用此方法来显示与搜索匹配的前两个制造商。搜索结果与过滤器 manu_id_s:apple 匹配,但计算出的分面会丢弃此过滤器,并操作通过丢弃 manu_id_s 过滤器而加宽的域。

  • curl

  • SolrJ

curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
  "query": "cat:electronics",
  "filter": "{!tag=MANU}manu_id_s:apple",
  "facet": {
    "stock": {"type": "terms", "field": "inStock", "limit": 2},
    "manufacturers": {
      "type": "terms",
      "field": "manu_id_s",
      "limit": 2,
      "domain": { "excludeTags":"MANU" }
    }
  }
}'
final TermsFacetMap inStockFacet = new TermsFacetMap("inStock").setLimit(2);
final TermsFacetMap allManufacturersFacet =
    new TermsFacetMap("manu_id_s")
        .setLimit(2)
        .withDomain(new DomainMap().withTagsToExclude("MANU"));
final JsonQueryRequest request =
    new JsonQueryRequest()
        .setQuery("cat:electronics")
        .withFilter("{!tag=MANU}manu_id_s:apple")
        .withFacet("stock", inStockFacet)
        .withFacet("manufacturers", allManufacturersFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);

excludeTags 的值可以是单个字符串标记、字符串标记数组或单个字符串中以逗号分隔的标记。

excludeTags 选项与其他 domain 更改选项组合使用时,它会在任何其他域更改发生之前扩展域。

另请参阅关于多选分面的部分。

任意域查询

当您希望针对任意一组文档计算分面,而不管原始域是什么时,可以指定一个 query 域。最常见的用例是针对集合的特定子集计算顶级分面,而不管主查询是什么。但在构建语义知识图时,它在嵌套分面上也很有用。

示例

  • curl

  • SolrJ

curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
  "query": "apple",
  "facet": {
    "popular_categories": {
      "type": "terms",
      "field": "cat",
      "domain": { "query": "popularity:[8 TO 10]" },
      "limit": 3
    }
  }
}'
final TermsFacetMap inStockFacet = new TermsFacetMap("inStock").setLimit(2);
final TermsFacetMap popularCategoriesFacet =
    new TermsFacetMap("cat")
        .withDomain(new DomainMap().withQuery("popularity:[8 TO 10]"))
        .setLimit(3);
final JsonQueryRequest request =
    new JsonQueryRequest()
        .setQuery("apple")
        .withFacet("popular_categories", popularCategoriesFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);

query 的值可以是单个查询,也可以是查询的 JSON 列表。每个查询可以是:

  • 一个包含 Solr 查询语法的查询字符串。

  • 引用包含 Solr 查询语法的请求参数,形式为:{param: <request_param_name>}。引用的参数可能具有 0 个(不存在)或多个值。

    • 当没有指定值时,不会抛出错误。

    • 当指定了多个值时,每个值都会被解析并用作查询。

虽然 query 域可以与附加的域 filter 结合使用,但不能同时使用 excludeTags,因为标签将毫无意义:query 域已经完全忽略了顶级查询和所有先前的过滤器。

块连接域更改

当集合包含嵌套文档时,可以使用 blockChildrenblockParent 域选项将包含一种类型文档的现有域转换为包含与原始域文档具有指定关系(子级或父级)的文档的域。

这两个选项的工作方式类似于相应的块连接查询解析器,它接收一个字符串查询,该查询专门匹配集合中的所有父文档。如果使用 blockParent,则生成的域将包含来自原始域的子文档的所有父文档。如果使用 blockChildren,则生成的域将包含来自原始域的父文档的所有子文档。通常,需要对父文档中的子文档进行计数,这可以通过 uniqueBlock(_root_) 来完成,如块连接分面计数中所述。

{
  "colors": {                         (1)
    "type": "terms",
    "field": "sku_color",             (2)
    "facet" : {
      "brands" : {
        "type": "terms",
        "field": "product_brand",     (3)
        "domain": {
          "blockParent": "doc_type:product"
        }
      }}}}
1 此示例假设我们有对应于产品的父文档,以及对应于具有唯一颜色的单个 SKU 的子文档,并且我们的原始查询是针对 SKU 文档的。
2 colors 分面将针对与我们的搜索匹配的所有原始 SKU 文档进行计算。
3 对于 colors 分面中的每个存储桶,所有匹配的 SKU 文档的集合将转换为相应的父产品文档的集合。生成的 brands 子分面将计算每个品牌存在多少个产品文档(这些文档具有与该颜色关联的 SKU)。

连接查询域更改

可以使用 join 域更改选项来指定任意的 fromto 字段,以便从现有域转换到相关的文档集。

这类似于连接查询解析器的工作方式,并且在处理多碎片集合时具有相同的限制。

示例

{
  "colors": {
    "type": "terms",
    "field": "sku_color",
    "facet": {
      "brands": {
        "type": "terms",
        "field": "product_brand",
        "domain" : {
          "join" : {
            "from": "product_id_of_this_sku",
            "to": "id"
          },
          "filter": "doc_type:product"
        }
      }
    }
  }
}

join 域更改支持可选的 method 参数,该参数允许用户指定他们希望在此域转换中使用哪个连接实现。Solr 提供了几种连接实现,每种实现都具有不同的性能特征。有关这些实现及其权衡的更多信息,请参阅method 参数文档。连接域更改支持除 crossCollection 之外的所有 method 值。

图遍历域更改

graph 域更改选项的工作方式类似于 join 域选项,但可以从现有域到其他文档进行多次跳跃 from 遍历。

这与图查询解析器非常相似,支持其所有可选参数,并且在处理多碎片集合时具有相同的限制。

示例

{
  "related_brands": {
    "type": "terms",
    "field": "brand",
    "domain": {
      "graph": {
        "from": "related_product_ids",
        "to": "id",
        "maxDepth": 3
      }
    }
  }
}