0
votes

I'm trying to perform faceting based on a dynamic value. Basically I want identical behavior to the def function, but that doesn't seem to be available with faceting.

Consider these two "products":

{
  "id":"product1",
  "defaultPrice":19.99,
  "overridePrice":14.99
},
{
  "id":"product2",
  "defaultPrice":49.99
}

I want to add that overridePrice is just an example. The actual field is a dynamic value that will depend on what context a search is performed in, and there may be many overridden prices, so I can't just derive price at index time.

For the response, I'm doing something like this for fl:

fl=price:def(overridePrice, defaultPrice) and using the same def function to perform sorting on price. This works fine.

So now I want to apply the same logic to facets. I've tried using json.facet, which seemed like it would work:

json.facet={
  price: "def(overridePrice, defaultPrice)"
}

I've tried other variations as well, such as using field:def(overridePrice, defaultPrice) as well as field:price, but def doesn't seem to be an available function for faceting, and the price derived field is not available when faceting.

So the question: How can I perform faceting based on a default field like I'm doing for fl and sorting? Will this require a custom aggregation function, or is there a clever way I can do this without a custom function? It would be much more preferable to be able to do this with built-in Solr functionality.

1

1 Answers

0
votes

I was able to do a hacky solution based on a tip in another question.

We can use two facets with a query to filter documents depending on if a field exists.

Example:

{
  price_override: {
    type: query,
    q: "overridePrice:[* TO *]",
    facet: {
      price_override:{
        type:terms,
        field: overridePrice
      }
    }
  },
  price_standard: {
    type: query,
    q: "-overridePrice:[* TO *] AND defaultPrice:[* TO *]",
    facet: {
        price_standard: {
        type: terms,
        field: defaultPrice
      }
    }
  }
}

Explanation:

price_override: {
        type: query,
        q: "overridePrice:[* TO *]"

This range query only selects documents that have an overridePrice field.

price_standard: {
        type: query,
        q: "-overridePrice:[* TO *] AND defaultPrice:[* TO *]"

-overridePrice:[* TO *] omits documents with the overridePrice field, and selects documents with a defaultPrice field.

And the facet response:

"facets":{
    "count":2,
    "price_override":{
      "count":1,
      "price_override":{
        "buckets":[{
            "val":14.99,
            "count":1}]}},
    "price_standard":{
      "count":1,
      "price_standard":{
        "buckets":[{
            "val":49.99,
            "count":1}]}}}

This does require manually grouping price_override and price_standard into a single facet group, but the results are as expected. This could also pretty easily be tweaked into a ranged query, which is my use case.