You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-user@lucene.apache.org by James Bodkin <ja...@loveholidays.com> on 2020/06/11 13:39:02 UTC

Facet Performance

We’ve been running a load test against our index and have noticed that the facet queries are significantly slower than we would like.
Currently these types of queries are taking several seconds to execute and are wondering if it would be possible to speed these up.
Repeating the same query over and over does not improve the response time so does not appear to utilise any caching.
Ideally we would like to be targeting a response time around tens or hundreds of milliseconds if possible.

An example query that is taking around 2-3 seconds to execute is:

q=*.*
facet=true
facet.field=D_UserRatingGte
facet.mincount=1
facet.limit=-1
rows=0

"response":{"numFound":18979503,"start":0,"maxScore":1.0,"docs":[]}
"facet_counts":{
    "facet_queries":{},
    "facet_fields":{
      "D_UserRatingGte":[
        "1575",16614238,
        "1576",16614238,
        "1577",16614238,
        "1578",16065938,
        "1579",12079545,
        "1580",458799]},
    "facet_ranges":{},
    "facet_intervals":{},
    "facet_heatmaps":{}}}

I have also tried the equivalent query using the JSON Facet API with the same outcome of slow response time.
Additionally I have tried changing the facet method (on both facet apis) with the same outcome of slow response time.

The underlying field for the above query is configured as a solr.IntPointField with docValues, indexed and multiValued set to true.
The index has just under 19 million documents and the physical size on disk is 10.95GB. The index is read-only and consists of 4 segments with 0 deletions.
We’re running standalone Solr 8.3.1 with a 8GB Heap and the underlying Google Cloud Virtual Machine in our load test environment has 6 vCPUs, 32G RAM and 100GB SSD.

Would anyone be able to point me in a direction to either improve the performance or understand the current performance is expected?

Kind Regards,

James Bodkin

Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
Could you explain why the performance is an issue for points-based fields? I've looked through the referenced issue (which is fixed in the version we are running) but I'm missing the link between the two. Is there an issue to improve this for points-based fields?
We're going to change the field type to a string, as our queries are always looking for a specific value (and not intervals/ranges) and rerun our load test.


Kind Regards,

James Bodkin

On 11/06/2020, 14:49, "Erick Erickson" <er...@gmail.com> wrote:

    There’s a lot of confusion about using points-based fields for faceting, see: https://issues.apache.org/jira/browse/SOLR-13227 for instance.

    Two options you might try:
    1> copyField to a string field and facet on that (won’t work, of course, for any kind of interval/range facet)
    2> use the deprecated Trie field instead. You could use the copyField to a Trie field for this too.

    Best,
    Erick


Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
queryResultCache doesn’t really help with faceting, even if it’s hit for the main query. 
That cache only stores a subset of the hits, and to facet properly you need 
the entire result set….

> On Jun 17, 2020, at 12:47 PM, James Bodkin <ja...@loveholidays.com> wrote:
> 
> We've noticed that the filterCache uses a significant amount of memory, as we've assigned 8GB Heap per instance.
> In total, we have 32 shards with 2 replicas, hence (8*32*2) 512G Heap space alone, further memory is required to ensure the index is always memory mapped for performance reasons.
> 
> Ideally I would like to be able to reduce the amount of memory assigned to the heap by using docValues instead of indexed but it doesn't seem possible.
> The QTime (after warming) for facet.method=enum is around 150-250ms whereas the QTime for facet.method=fc is around 1000-1200ms.
> As we require the results in real-time for customers searching on our website, the later QTime of 1000-1200ms is too slow for us to be able to use.
> 
> Our facet queries change as the customer selects different search criteria, and hence the possible number of potential queries makes it very difficult for the query result cache.
> We already have a custom implementation in which we check our redis cache for queries before they are sent to our aggregators which runs at 30% hit rate.
> 
> Kind Regards,
> 
> James Bodkin
> 
> On 17/06/2020, 16:21, "Michael Gibney" <mi...@michaelgibney.net> wrote:
> 
>    To expand a bit on what Erick said regarding performance: my sense is
>    that the RefGuide assertion that "docValues=true" makes faceting
>    "faster" could use some qualification/clarification. My take, fwiw:
> 
>    First, to reiterate/paraphrase what Erick said: the "faster" assertion
>    is not comparing to "facet.method=enum". For low-cardinality fields,
>    if you have the heap space, and are very intentional about configuring
>    your filterCache (and monitoring it as access patterns might change),
>    "facet.method=enum" will likely be as fast as you can get (at least
>    for "legacy" facets or whatever -- not sure about "enum" method in
>    JSON facets).
> 
>    Even where "docValues=true" arguably does make faceting "faster", the
>    main benefit is that the "uninverted" data structures are serialized
>    on disk, so you're avoiding the need to uninvert each facet field
>    on-heap for every new indexSearcher, which is generally high-latency
>    -- user perception of this latency can be mitigated using warming
>    queries, but it can still be problematic, esp. for frequent index
>    updates. On-heap uninversion also inherently consumes a lot of heap
>    space, which has general implications wrt GC, etc ... so in that
>    respect even if faceting per se might not be "faster" with
>    "docValues=true", your overall system may in many cases perform
>    better.
> 
>    (and Anthony, I'm pretty sure that tag/ex on facets should be
>    orthogonal to the "facet.method=enum"/filterCache discussion, as
>    tag/ex only affects the DocSet domain over which facets are calculated
>    ... I think that step is pretty cleanly separated from the actual
>    calculation of the facets. I'm not 100% sure on that, so proceed with
>    caution, but it could definitely be worth evaluating for your use
>    case!)
> 
>    Michael
> 
>    On Wed, Jun 17, 2020 at 10:42 AM Erick Erickson <er...@gmail.com> wrote:
>> 
>> Uninvertible is a safety mechanism to make sure that you don’t _unknowingly_ use a docValues=false
>> field for faceting/grouping/sorting/function queries. The primary point of docValues=true is twofold:
>> 
>> 1> reduce Java heap requirements by using the OS memory to hold it
>> 
>> 2> uninverting can be expensive CPU wise too, although not with just a few
>>    unique values (for each term, read the list of docs that have it and flip a bit).
>> 
>> It doesn’t really make sense to set it on an index=false field, since uninverting only happens on
>> index=true docValues=false. OTOH, I don’t think it would do any harm either. That said, I frankly
>> don’t know how that interacts with facet.method=enum.
>> 
>> As far as speed… yeah, you’re in the edge cases. All things being equal, stuffing these into the
>> filterCache is the fastest way to facet if you have the memory. I’ve seen very few installations
>> where people have that luxury though. Each entry in the filterCache can occupy maxDoc/8 + some overhead
>> bytes. If maxDoc is very large, this’ll chew up an enormous amount of memory. I’m cheating
>> a bit here since the size might be smaller if only a few docs have any particular entry then the
>> size is smaller. But that’s the worst-case you have to allow for ‘cause you could theoretically hit
>> the perfect storm where, due to some particular sequence of queries, your entire filter
>> cache fills up with entries that size.
>> 
>> You’ll have some overhead to keep the cache at that size, but it sounds like it’s worth it.
>> 
>> Best,
>> Erick
>> 
>> 
>> 
>>> On Jun 17, 2020, at 10:05 AM, James Bodkin <ja...@loveholidays.com> wrote:
>>> 
>>> The large majority of the relevant fields have fewer than 20 unique values. We have two fields over that with 150 unique values and 5300 unique values retrospectively.
>>> At the moment, our filterCache is configured with a maximum size of 8192.
>>> 
>>> From the DocValues documentation (https://lucene.apache.org/solr/guide/8_3/docvalues.html), it mentions that this approach promises to make lookups for faceting, sorting and grouping much faster.
>>> Hence I thought that using DocValues would be better than using Indexed and in turn improve our response times and possibly lower memory requirements. It sounds like this isn't the case if you are able to allocate enough memory to the filterCache.
>>> 
>>> I haven't yet tried changing the uninvertible setting, I was looking at the documentation for this field earlier today.
>>> Should we be setting uninvertible="false" if docValues="true" regardless of whether indexed is true or false?
>>> 
>>> Kind Regards,
>>> 
>>> James Bodkin
>>> 
>>> On 17/06/2020, 14:02, "Michael Gibney" <mi...@michaelgibney.net> wrote:
>>> 
>>>   facet.method=enum works by executing a query (against indexed values)
>>>   for each indexed value in a given field (which, for indexed=false, is
>>>   "no values"). So that explains why facet.method=enum no longer works.
>>>   I was going to suggest that you might not want to set indexed=false on
>>>   the docValues facet fields anyway, since the indexed values are still
>>>   used for facet refinement (assuming your index is distributed).
>>> 
>>>   What's the number of unique values in the relevant fields? If it's low
>>>   enough, setting docValues=false and indexed=true and using
>>>   facet.method=enum (with a sufficiently large filterCache) is
>>>   definitely a viable option, and will almost certainly be faster than
>>>   docValues-based faceting. (As an aside, noting for future reference:
>>>   high-cardinality facets over high-cardinality DocSet domains might be
>>>   able to benefit from a term facet count cache:
>>>   https://issues.apache.org/jira/browse/SOLR-13807)
>>> 
>>>   I think you didn't specifically mention whether you acted on Erick's
>>>   suggestion of setting "uninvertible=false" (I think Erick accidentally
>>>   said "uninvertible=true") to fail fast. I'd also recommend doing that,
>>>   perhaps even above all else -- it shouldn't actually *do* anything,
>>>   but will help ensure that things are behaving as you expect them to!
>>> 
>>>   Michael
>>> 
>>>   On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
>>>   <ja...@loveholidays.com> wrote:
>>>> 
>>>> Thanks, I've implemented some queries that improve the first-hit execution for faceting.
>>>> 
>>>> Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
>>>> Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
>>>> 
>>>> On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
>>>> 
>>>>   Ok, I see the disconnect... Necessary parts if the index are read from disk
>>>>   lazily. So your newSearcher or firstSearcher query needs to do whatever
>>>>   operation causes the relevant parts of the index to be read. In this case,
>>>>   probably just facet on all the fields you care about. I'd add sorting too
>>>>   if you sort on different fields.
>>>> 
>>>>   The *:* query without facets or sorting does virtually nothing due to some
>>>>   special handling...
>>>> 
>>>>   On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
>>>>   wrote:
>>>> 
>>>>> I've been trying to build a query that I can use in newSearcher based off
>>>>> the information in your previous e-mail. I thought you meant to build a *:*
>>>>> query as per Query 1 in my previous e-mail but I'm still seeing the
>>>>> first-hit execution.
>>>>> Now I'm wondering if you meant to create a *:* query with each of the
>>>>> fields as part of the fl query parameters or a *:* query with each of the
>>>>> fields and values as part of the fq query parameters.
>>>>> 
>>>>> At the moment I've been running these manually as I expected that I would
>>>>> see the first-execution penalty disappear by the time I got to query 4, as
>>>>> I thought this would replicate the actions of the newSeacher.
>>>>> Unfortunately we can't use the autowarm count that is available as part of
>>>>> the filterCache/filterCache due to the custom deployment mechanism we use
>>>>> to update our index.
>>>>> 
>>>>> Kind Regards,
>>>>> 
>>>>> James Bodkin
>>>>> 
>>>>> On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
>>>>> 
>>>>>   Did you try the autowarming like I mentioned in my previous e-mail?
>>>>> 
>>>>>> On Jun 16, 2020, at 10:18 AM, James Bodkin <
>>>>> james.bodkin@loveholidays.com> wrote:
>>>>>> 
>>>>>> We've changed the schema to enable docValues for these fields and
>>>>> this led to an improvement in the response time. We found a further
>>>>> improvement by also switching off indexed as these fields are used for
>>>>> faceting and filtering only.
>>>>>> Since those changes, we've found that the first-execution for
>>>>> queries is really noticeable. I thought this would be the filterCache based
>>>>> on what I saw in NewRelic however it is probably trying to read the
>>>>> docValues from disk. How can we use the autowarming to improve this?
>>>>>> 
>>>>>> For example, I've run the following queries in sequence and each
>>>>> query has a first-execution penalty.
>>>>>> 
>>>>>> Query 1:
>>>>>> 
>>>>>> q=*:*
>>>>>> facet=true
>>>>>> facet.field=D_DepartureAirport
>>>>>> facet.field=D_Destination
>>>>>> facet.limit=-1
>>>>>> rows=0
>>>>>> 
>>>>>> Query 2:
>>>>>> 
>>>>>> q=*:*
>>>>>> fq=D_DepartureAirport:(2660)
>>>>>> facet=true
>>>>>> facet.field=D_Destination
>>>>>> facet.limit=-1
>>>>>> rows=0
>>>>>> 
>>>>>> Query 3:
>>>>>> 
>>>>>> q=*:*
>>>>>> fq=D_DepartureAirport:(2661)
>>>>>> facet=true
>>>>>> facet.field=D_Destination
>>>>>> facet.limit=-1
>>>>>> rows=0
>>>>>> 
>>>>>> Query 4:
>>>>>> 
>>>>>> q=*:*
>>>>>> fq=D_DepartureAirport:(2660+OR+2661)
>>>>>> facet=true
>>>>>> facet.field=D_Destination
>>>>>> facet.limit=-1
>>>>>> rows=0
>>>>>> 
>>>>>> We've kept the field type as a string, as the value is mapped by
>>>>> application that accesses Solr. In the examples above, the values are
>>>>> mapped to airports and destinations.
>>>>>> Is it possible to prewarm the above queries without having to define
>>>>> all the potential filters manually in the auto warming?
>>>>>> 
>>>>>> At the moment, we update and optimise our index in a different
>>>>> environment and then copy the index to our production instances by using a
>>>>> rolling deployment in Kubernetes.
>>>>>> 
>>>>>> Kind Regards,
>>>>>> 
>>>>>> James Bodkin
>>>>>> 
>>>>>> On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
>>>>> wrote:
>>>>>> 
>>>>>>  I question whether fiterCache has anything to do with it, I
>>>>> suspect what’s really happening is that first time you’re reading the
>>>>> relevant bits from disk into memory. And to double check you should have
>>>>> docVaues enabled for all these fields. The “uninverting” process  can be
>>>>> very expensive, and docValues bypasses that.
>>>>>> 
>>>>>>  As of Solr 7.6, you can define “uninvertible=true” to your
>>>>> field(Type) to “fail fast” if Solr needs to uninvert the field.
>>>>>> 
>>>>>>  But that’s an aside. In either case, my claim is that first-time
>>>>> execution does “something”, either reads the serialized docValues from disk
>>>>> or uninverts the file on Solr’s heap.
>>>>>> 
>>>>>>  You can have this autowarmed by any combination of
>>>>>>  1> specifying an autowarm count on your queryResultCache. That’s
>>>>> hit or miss, as it replays the most recent N queries which may or may not
>>>>> contain the sorts. That said, specifying 10-20 for autowarm count is
>>>>> usually a good idea, assuming you’re not committing more than, say, every
>>>>> 30 seconds. I’d add the same to filterCache too.
>>>>>> 
>>>>>>  2> specifying a newSearcher or firstSearcher query in
>>>>> solrconfig.xml. The difference is that newSearcher is fired every time a
>>>>> commit happens, while firstSearcher is only fired when Solr starts, the
>>>>> theory being that there’s no cache autowarming available when Solr fist
>>>>> powers up. Usually, people don’t bother with firstSearcher or just make it
>>>>> the same as newSearcher. Note that a query doesn’t have to be “real” at
>>>>> all. You can just add all the facet fields to a *:* query in a single go.
>>>>>> 
>>>>>>  BTW, Trie fields will stay around for a long time even though
>>>>> deprecated. Or at least until we find something to replace them with that
>>>>> doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
>>>>> be more efficient than strings.
>>>>>> 
>>>>>>  Best,
>>>>>>  Erick
>>>>>> 
>>>>> 
>>>>> 
>> 


Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
We've noticed that the filterCache uses a significant amount of memory, as we've assigned 8GB Heap per instance.
In total, we have 32 shards with 2 replicas, hence (8*32*2) 512G Heap space alone, further memory is required to ensure the index is always memory mapped for performance reasons.

Ideally I would like to be able to reduce the amount of memory assigned to the heap by using docValues instead of indexed but it doesn't seem possible.
The QTime (after warming) for facet.method=enum is around 150-250ms whereas the QTime for facet.method=fc is around 1000-1200ms.
As we require the results in real-time for customers searching on our website, the later QTime of 1000-1200ms is too slow for us to be able to use.

Our facet queries change as the customer selects different search criteria, and hence the possible number of potential queries makes it very difficult for the query result cache.
We already have a custom implementation in which we check our redis cache for queries before they are sent to our aggregators which runs at 30% hit rate.

Kind Regards,

James Bodkin

On 17/06/2020, 16:21, "Michael Gibney" <mi...@michaelgibney.net> wrote:

    To expand a bit on what Erick said regarding performance: my sense is
    that the RefGuide assertion that "docValues=true" makes faceting
    "faster" could use some qualification/clarification. My take, fwiw:

    First, to reiterate/paraphrase what Erick said: the "faster" assertion
    is not comparing to "facet.method=enum". For low-cardinality fields,
    if you have the heap space, and are very intentional about configuring
    your filterCache (and monitoring it as access patterns might change),
    "facet.method=enum" will likely be as fast as you can get (at least
    for "legacy" facets or whatever -- not sure about "enum" method in
    JSON facets).

    Even where "docValues=true" arguably does make faceting "faster", the
    main benefit is that the "uninverted" data structures are serialized
    on disk, so you're avoiding the need to uninvert each facet field
    on-heap for every new indexSearcher, which is generally high-latency
    -- user perception of this latency can be mitigated using warming
    queries, but it can still be problematic, esp. for frequent index
    updates. On-heap uninversion also inherently consumes a lot of heap
    space, which has general implications wrt GC, etc ... so in that
    respect even if faceting per se might not be "faster" with
    "docValues=true", your overall system may in many cases perform
    better.

    (and Anthony, I'm pretty sure that tag/ex on facets should be
    orthogonal to the "facet.method=enum"/filterCache discussion, as
    tag/ex only affects the DocSet domain over which facets are calculated
    ... I think that step is pretty cleanly separated from the actual
    calculation of the facets. I'm not 100% sure on that, so proceed with
    caution, but it could definitely be worth evaluating for your use
    case!)

    Michael

    On Wed, Jun 17, 2020 at 10:42 AM Erick Erickson <er...@gmail.com> wrote:
    >
    > Uninvertible is a safety mechanism to make sure that you don’t _unknowingly_ use a docValues=false
    > field for faceting/grouping/sorting/function queries. The primary point of docValues=true is twofold:
    >
    > 1> reduce Java heap requirements by using the OS memory to hold it
    >
    > 2> uninverting can be expensive CPU wise too, although not with just a few
    >     unique values (for each term, read the list of docs that have it and flip a bit).
    >
    > It doesn’t really make sense to set it on an index=false field, since uninverting only happens on
    > index=true docValues=false. OTOH, I don’t think it would do any harm either. That said, I frankly
    > don’t know how that interacts with facet.method=enum.
    >
    > As far as speed… yeah, you’re in the edge cases. All things being equal, stuffing these into the
    > filterCache is the fastest way to facet if you have the memory. I’ve seen very few installations
    > where people have that luxury though. Each entry in the filterCache can occupy maxDoc/8 + some overhead
    > bytes. If maxDoc is very large, this’ll chew up an enormous amount of memory. I’m cheating
    > a bit here since the size might be smaller if only a few docs have any particular entry then the
    > size is smaller. But that’s the worst-case you have to allow for ‘cause you could theoretically hit
    > the perfect storm where, due to some particular sequence of queries, your entire filter
    > cache fills up with entries that size.
    >
    > You’ll have some overhead to keep the cache at that size, but it sounds like it’s worth it.
    >
    > Best,
    > Erick
    >
    >
    >
    > > On Jun 17, 2020, at 10:05 AM, James Bodkin <ja...@loveholidays.com> wrote:
    > >
    > > The large majority of the relevant fields have fewer than 20 unique values. We have two fields over that with 150 unique values and 5300 unique values retrospectively.
    > > At the moment, our filterCache is configured with a maximum size of 8192.
    > >
    > > From the DocValues documentation (https://lucene.apache.org/solr/guide/8_3/docvalues.html), it mentions that this approach promises to make lookups for faceting, sorting and grouping much faster.
    > > Hence I thought that using DocValues would be better than using Indexed and in turn improve our response times and possibly lower memory requirements. It sounds like this isn't the case if you are able to allocate enough memory to the filterCache.
    > >
    > > I haven't yet tried changing the uninvertible setting, I was looking at the documentation for this field earlier today.
    > > Should we be setting uninvertible="false" if docValues="true" regardless of whether indexed is true or false?
    > >
    > > Kind Regards,
    > >
    > > James Bodkin
    > >
    > > On 17/06/2020, 14:02, "Michael Gibney" <mi...@michaelgibney.net> wrote:
    > >
    > >    facet.method=enum works by executing a query (against indexed values)
    > >    for each indexed value in a given field (which, for indexed=false, is
    > >    "no values"). So that explains why facet.method=enum no longer works.
    > >    I was going to suggest that you might not want to set indexed=false on
    > >    the docValues facet fields anyway, since the indexed values are still
    > >    used for facet refinement (assuming your index is distributed).
    > >
    > >    What's the number of unique values in the relevant fields? If it's low
    > >    enough, setting docValues=false and indexed=true and using
    > >    facet.method=enum (with a sufficiently large filterCache) is
    > >    definitely a viable option, and will almost certainly be faster than
    > >    docValues-based faceting. (As an aside, noting for future reference:
    > >    high-cardinality facets over high-cardinality DocSet domains might be
    > >    able to benefit from a term facet count cache:
    > >    https://issues.apache.org/jira/browse/SOLR-13807)
    > >
    > >    I think you didn't specifically mention whether you acted on Erick's
    > >    suggestion of setting "uninvertible=false" (I think Erick accidentally
    > >    said "uninvertible=true") to fail fast. I'd also recommend doing that,
    > >    perhaps even above all else -- it shouldn't actually *do* anything,
    > >    but will help ensure that things are behaving as you expect them to!
    > >
    > >    Michael
    > >
    > >    On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
    > >    <ja...@loveholidays.com> wrote:
    > >>
    > >> Thanks, I've implemented some queries that improve the first-hit execution for faceting.
    > >>
    > >> Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
    > >> Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
    > >>
    > >> On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
    > >>
    > >>    Ok, I see the disconnect... Necessary parts if the index are read from disk
    > >>    lazily. So your newSearcher or firstSearcher query needs to do whatever
    > >>    operation causes the relevant parts of the index to be read. In this case,
    > >>    probably just facet on all the fields you care about. I'd add sorting too
    > >>    if you sort on different fields.
    > >>
    > >>    The *:* query without facets or sorting does virtually nothing due to some
    > >>    special handling...
    > >>
    > >>    On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
    > >>    wrote:
    > >>
    > >>> I've been trying to build a query that I can use in newSearcher based off
    > >>> the information in your previous e-mail. I thought you meant to build a *:*
    > >>> query as per Query 1 in my previous e-mail but I'm still seeing the
    > >>> first-hit execution.
    > >>> Now I'm wondering if you meant to create a *:* query with each of the
    > >>> fields as part of the fl query parameters or a *:* query with each of the
    > >>> fields and values as part of the fq query parameters.
    > >>>
    > >>> At the moment I've been running these manually as I expected that I would
    > >>> see the first-execution penalty disappear by the time I got to query 4, as
    > >>> I thought this would replicate the actions of the newSeacher.
    > >>> Unfortunately we can't use the autowarm count that is available as part of
    > >>> the filterCache/filterCache due to the custom deployment mechanism we use
    > >>> to update our index.
    > >>>
    > >>> Kind Regards,
    > >>>
    > >>> James Bodkin
    > >>>
    > >>> On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
    > >>>
    > >>>    Did you try the autowarming like I mentioned in my previous e-mail?
    > >>>
    > >>>> On Jun 16, 2020, at 10:18 AM, James Bodkin <
    > >>> james.bodkin@loveholidays.com> wrote:
    > >>>>
    > >>>> We've changed the schema to enable docValues for these fields and
    > >>> this led to an improvement in the response time. We found a further
    > >>> improvement by also switching off indexed as these fields are used for
    > >>> faceting and filtering only.
    > >>>> Since those changes, we've found that the first-execution for
    > >>> queries is really noticeable. I thought this would be the filterCache based
    > >>> on what I saw in NewRelic however it is probably trying to read the
    > >>> docValues from disk. How can we use the autowarming to improve this?
    > >>>>
    > >>>> For example, I've run the following queries in sequence and each
    > >>> query has a first-execution penalty.
    > >>>>
    > >>>> Query 1:
    > >>>>
    > >>>> q=*:*
    > >>>> facet=true
    > >>>> facet.field=D_DepartureAirport
    > >>>> facet.field=D_Destination
    > >>>> facet.limit=-1
    > >>>> rows=0
    > >>>>
    > >>>> Query 2:
    > >>>>
    > >>>> q=*:*
    > >>>> fq=D_DepartureAirport:(2660)
    > >>>> facet=true
    > >>>> facet.field=D_Destination
    > >>>> facet.limit=-1
    > >>>> rows=0
    > >>>>
    > >>>> Query 3:
    > >>>>
    > >>>> q=*:*
    > >>>> fq=D_DepartureAirport:(2661)
    > >>>> facet=true
    > >>>> facet.field=D_Destination
    > >>>> facet.limit=-1
    > >>>> rows=0
    > >>>>
    > >>>> Query 4:
    > >>>>
    > >>>> q=*:*
    > >>>> fq=D_DepartureAirport:(2660+OR+2661)
    > >>>> facet=true
    > >>>> facet.field=D_Destination
    > >>>> facet.limit=-1
    > >>>> rows=0
    > >>>>
    > >>>> We've kept the field type as a string, as the value is mapped by
    > >>> application that accesses Solr. In the examples above, the values are
    > >>> mapped to airports and destinations.
    > >>>> Is it possible to prewarm the above queries without having to define
    > >>> all the potential filters manually in the auto warming?
    > >>>>
    > >>>> At the moment, we update and optimise our index in a different
    > >>> environment and then copy the index to our production instances by using a
    > >>> rolling deployment in Kubernetes.
    > >>>>
    > >>>> Kind Regards,
    > >>>>
    > >>>> James Bodkin
    > >>>>
    > >>>> On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
    > >>> wrote:
    > >>>>
    > >>>>   I question whether fiterCache has anything to do with it, I
    > >>> suspect what’s really happening is that first time you’re reading the
    > >>> relevant bits from disk into memory. And to double check you should have
    > >>> docVaues enabled for all these fields. The “uninverting” process  can be
    > >>> very expensive, and docValues bypasses that.
    > >>>>
    > >>>>   As of Solr 7.6, you can define “uninvertible=true” to your
    > >>> field(Type) to “fail fast” if Solr needs to uninvert the field.
    > >>>>
    > >>>>   But that’s an aside. In either case, my claim is that first-time
    > >>> execution does “something”, either reads the serialized docValues from disk
    > >>> or uninverts the file on Solr’s heap.
    > >>>>
    > >>>>   You can have this autowarmed by any combination of
    > >>>>   1> specifying an autowarm count on your queryResultCache. That’s
    > >>> hit or miss, as it replays the most recent N queries which may or may not
    > >>> contain the sorts. That said, specifying 10-20 for autowarm count is
    > >>> usually a good idea, assuming you’re not committing more than, say, every
    > >>> 30 seconds. I’d add the same to filterCache too.
    > >>>>
    > >>>>   2> specifying a newSearcher or firstSearcher query in
    > >>> solrconfig.xml. The difference is that newSearcher is fired every time a
    > >>> commit happens, while firstSearcher is only fired when Solr starts, the
    > >>> theory being that there’s no cache autowarming available when Solr fist
    > >>> powers up. Usually, people don’t bother with firstSearcher or just make it
    > >>> the same as newSearcher. Note that a query doesn’t have to be “real” at
    > >>> all. You can just add all the facet fields to a *:* query in a single go.
    > >>>>
    > >>>>   BTW, Trie fields will stay around for a long time even though
    > >>> deprecated. Or at least until we find something to replace them with that
    > >>> doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
    > >>> be more efficient than strings.
    > >>>>
    > >>>>   Best,
    > >>>>   Erick
    > >>>>
    > >>>
    > >>>
    >

Re: Facet Performance

Posted by Michael Gibney <mi...@michaelgibney.net>.
To expand a bit on what Erick said regarding performance: my sense is
that the RefGuide assertion that "docValues=true" makes faceting
"faster" could use some qualification/clarification. My take, fwiw:

First, to reiterate/paraphrase what Erick said: the "faster" assertion
is not comparing to "facet.method=enum". For low-cardinality fields,
if you have the heap space, and are very intentional about configuring
your filterCache (and monitoring it as access patterns might change),
"facet.method=enum" will likely be as fast as you can get (at least
for "legacy" facets or whatever -- not sure about "enum" method in
JSON facets).

Even where "docValues=true" arguably does make faceting "faster", the
main benefit is that the "uninverted" data structures are serialized
on disk, so you're avoiding the need to uninvert each facet field
on-heap for every new indexSearcher, which is generally high-latency
-- user perception of this latency can be mitigated using warming
queries, but it can still be problematic, esp. for frequent index
updates. On-heap uninversion also inherently consumes a lot of heap
space, which has general implications wrt GC, etc ... so in that
respect even if faceting per se might not be "faster" with
"docValues=true", your overall system may in many cases perform
better.

(and Anthony, I'm pretty sure that tag/ex on facets should be
orthogonal to the "facet.method=enum"/filterCache discussion, as
tag/ex only affects the DocSet domain over which facets are calculated
... I think that step is pretty cleanly separated from the actual
calculation of the facets. I'm not 100% sure on that, so proceed with
caution, but it could definitely be worth evaluating for your use
case!)

Michael

On Wed, Jun 17, 2020 at 10:42 AM Erick Erickson <er...@gmail.com> wrote:
>
> Uninvertible is a safety mechanism to make sure that you don’t _unknowingly_ use a docValues=false
> field for faceting/grouping/sorting/function queries. The primary point of docValues=true is twofold:
>
> 1> reduce Java heap requirements by using the OS memory to hold it
>
> 2> uninverting can be expensive CPU wise too, although not with just a few
>     unique values (for each term, read the list of docs that have it and flip a bit).
>
> It doesn’t really make sense to set it on an index=false field, since uninverting only happens on
> index=true docValues=false. OTOH, I don’t think it would do any harm either. That said, I frankly
> don’t know how that interacts with facet.method=enum.
>
> As far as speed… yeah, you’re in the edge cases. All things being equal, stuffing these into the
> filterCache is the fastest way to facet if you have the memory. I’ve seen very few installations
> where people have that luxury though. Each entry in the filterCache can occupy maxDoc/8 + some overhead
> bytes. If maxDoc is very large, this’ll chew up an enormous amount of memory. I’m cheating
> a bit here since the size might be smaller if only a few docs have any particular entry then the
> size is smaller. But that’s the worst-case you have to allow for ‘cause you could theoretically hit
> the perfect storm where, due to some particular sequence of queries, your entire filter
> cache fills up with entries that size.
>
> You’ll have some overhead to keep the cache at that size, but it sounds like it’s worth it.
>
> Best,
> Erick
>
>
>
> > On Jun 17, 2020, at 10:05 AM, James Bodkin <ja...@loveholidays.com> wrote:
> >
> > The large majority of the relevant fields have fewer than 20 unique values. We have two fields over that with 150 unique values and 5300 unique values retrospectively.
> > At the moment, our filterCache is configured with a maximum size of 8192.
> >
> > From the DocValues documentation (https://lucene.apache.org/solr/guide/8_3/docvalues.html), it mentions that this approach promises to make lookups for faceting, sorting and grouping much faster.
> > Hence I thought that using DocValues would be better than using Indexed and in turn improve our response times and possibly lower memory requirements. It sounds like this isn't the case if you are able to allocate enough memory to the filterCache.
> >
> > I haven't yet tried changing the uninvertible setting, I was looking at the documentation for this field earlier today.
> > Should we be setting uninvertible="false" if docValues="true" regardless of whether indexed is true or false?
> >
> > Kind Regards,
> >
> > James Bodkin
> >
> > On 17/06/2020, 14:02, "Michael Gibney" <mi...@michaelgibney.net> wrote:
> >
> >    facet.method=enum works by executing a query (against indexed values)
> >    for each indexed value in a given field (which, for indexed=false, is
> >    "no values"). So that explains why facet.method=enum no longer works.
> >    I was going to suggest that you might not want to set indexed=false on
> >    the docValues facet fields anyway, since the indexed values are still
> >    used for facet refinement (assuming your index is distributed).
> >
> >    What's the number of unique values in the relevant fields? If it's low
> >    enough, setting docValues=false and indexed=true and using
> >    facet.method=enum (with a sufficiently large filterCache) is
> >    definitely a viable option, and will almost certainly be faster than
> >    docValues-based faceting. (As an aside, noting for future reference:
> >    high-cardinality facets over high-cardinality DocSet domains might be
> >    able to benefit from a term facet count cache:
> >    https://issues.apache.org/jira/browse/SOLR-13807)
> >
> >    I think you didn't specifically mention whether you acted on Erick's
> >    suggestion of setting "uninvertible=false" (I think Erick accidentally
> >    said "uninvertible=true") to fail fast. I'd also recommend doing that,
> >    perhaps even above all else -- it shouldn't actually *do* anything,
> >    but will help ensure that things are behaving as you expect them to!
> >
> >    Michael
> >
> >    On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
> >    <ja...@loveholidays.com> wrote:
> >>
> >> Thanks, I've implemented some queries that improve the first-hit execution for faceting.
> >>
> >> Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
> >> Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
> >>
> >> On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
> >>
> >>    Ok, I see the disconnect... Necessary parts if the index are read from disk
> >>    lazily. So your newSearcher or firstSearcher query needs to do whatever
> >>    operation causes the relevant parts of the index to be read. In this case,
> >>    probably just facet on all the fields you care about. I'd add sorting too
> >>    if you sort on different fields.
> >>
> >>    The *:* query without facets or sorting does virtually nothing due to some
> >>    special handling...
> >>
> >>    On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
> >>    wrote:
> >>
> >>> I've been trying to build a query that I can use in newSearcher based off
> >>> the information in your previous e-mail. I thought you meant to build a *:*
> >>> query as per Query 1 in my previous e-mail but I'm still seeing the
> >>> first-hit execution.
> >>> Now I'm wondering if you meant to create a *:* query with each of the
> >>> fields as part of the fl query parameters or a *:* query with each of the
> >>> fields and values as part of the fq query parameters.
> >>>
> >>> At the moment I've been running these manually as I expected that I would
> >>> see the first-execution penalty disappear by the time I got to query 4, as
> >>> I thought this would replicate the actions of the newSeacher.
> >>> Unfortunately we can't use the autowarm count that is available as part of
> >>> the filterCache/filterCache due to the custom deployment mechanism we use
> >>> to update our index.
> >>>
> >>> Kind Regards,
> >>>
> >>> James Bodkin
> >>>
> >>> On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
> >>>
> >>>    Did you try the autowarming like I mentioned in my previous e-mail?
> >>>
> >>>> On Jun 16, 2020, at 10:18 AM, James Bodkin <
> >>> james.bodkin@loveholidays.com> wrote:
> >>>>
> >>>> We've changed the schema to enable docValues for these fields and
> >>> this led to an improvement in the response time. We found a further
> >>> improvement by also switching off indexed as these fields are used for
> >>> faceting and filtering only.
> >>>> Since those changes, we've found that the first-execution for
> >>> queries is really noticeable. I thought this would be the filterCache based
> >>> on what I saw in NewRelic however it is probably trying to read the
> >>> docValues from disk. How can we use the autowarming to improve this?
> >>>>
> >>>> For example, I've run the following queries in sequence and each
> >>> query has a first-execution penalty.
> >>>>
> >>>> Query 1:
> >>>>
> >>>> q=*:*
> >>>> facet=true
> >>>> facet.field=D_DepartureAirport
> >>>> facet.field=D_Destination
> >>>> facet.limit=-1
> >>>> rows=0
> >>>>
> >>>> Query 2:
> >>>>
> >>>> q=*:*
> >>>> fq=D_DepartureAirport:(2660)
> >>>> facet=true
> >>>> facet.field=D_Destination
> >>>> facet.limit=-1
> >>>> rows=0
> >>>>
> >>>> Query 3:
> >>>>
> >>>> q=*:*
> >>>> fq=D_DepartureAirport:(2661)
> >>>> facet=true
> >>>> facet.field=D_Destination
> >>>> facet.limit=-1
> >>>> rows=0
> >>>>
> >>>> Query 4:
> >>>>
> >>>> q=*:*
> >>>> fq=D_DepartureAirport:(2660+OR+2661)
> >>>> facet=true
> >>>> facet.field=D_Destination
> >>>> facet.limit=-1
> >>>> rows=0
> >>>>
> >>>> We've kept the field type as a string, as the value is mapped by
> >>> application that accesses Solr. In the examples above, the values are
> >>> mapped to airports and destinations.
> >>>> Is it possible to prewarm the above queries without having to define
> >>> all the potential filters manually in the auto warming?
> >>>>
> >>>> At the moment, we update and optimise our index in a different
> >>> environment and then copy the index to our production instances by using a
> >>> rolling deployment in Kubernetes.
> >>>>
> >>>> Kind Regards,
> >>>>
> >>>> James Bodkin
> >>>>
> >>>> On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
> >>> wrote:
> >>>>
> >>>>   I question whether fiterCache has anything to do with it, I
> >>> suspect what’s really happening is that first time you’re reading the
> >>> relevant bits from disk into memory. And to double check you should have
> >>> docVaues enabled for all these fields. The “uninverting” process  can be
> >>> very expensive, and docValues bypasses that.
> >>>>
> >>>>   As of Solr 7.6, you can define “uninvertible=true” to your
> >>> field(Type) to “fail fast” if Solr needs to uninvert the field.
> >>>>
> >>>>   But that’s an aside. In either case, my claim is that first-time
> >>> execution does “something”, either reads the serialized docValues from disk
> >>> or uninverts the file on Solr’s heap.
> >>>>
> >>>>   You can have this autowarmed by any combination of
> >>>>   1> specifying an autowarm count on your queryResultCache. That’s
> >>> hit or miss, as it replays the most recent N queries which may or may not
> >>> contain the sorts. That said, specifying 10-20 for autowarm count is
> >>> usually a good idea, assuming you’re not committing more than, say, every
> >>> 30 seconds. I’d add the same to filterCache too.
> >>>>
> >>>>   2> specifying a newSearcher or firstSearcher query in
> >>> solrconfig.xml. The difference is that newSearcher is fired every time a
> >>> commit happens, while firstSearcher is only fired when Solr starts, the
> >>> theory being that there’s no cache autowarming available when Solr fist
> >>> powers up. Usually, people don’t bother with firstSearcher or just make it
> >>> the same as newSearcher. Note that a query doesn’t have to be “real” at
> >>> all. You can just add all the facet fields to a *:* query in a single go.
> >>>>
> >>>>   BTW, Trie fields will stay around for a long time even though
> >>> deprecated. Or at least until we find something to replace them with that
> >>> doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
> >>> be more efficient than strings.
> >>>>
> >>>>   Best,
> >>>>   Erick
> >>>>
> >>>
> >>>
>

Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
Uninvertible is a safety mechanism to make sure that you don’t _unknowingly_ use a docValues=false
field for faceting/grouping/sorting/function queries. The primary point of docValues=true is twofold:

1> reduce Java heap requirements by using the OS memory to hold it

2> uninverting can be expensive CPU wise too, although not with just a few
    unique values (for each term, read the list of docs that have it and flip a bit).

It doesn’t really make sense to set it on an index=false field, since uninverting only happens on
index=true docValues=false. OTOH, I don’t think it would do any harm either. That said, I frankly
don’t know how that interacts with facet.method=enum.

As far as speed… yeah, you’re in the edge cases. All things being equal, stuffing these into the
filterCache is the fastest way to facet if you have the memory. I’ve seen very few installations
where people have that luxury though. Each entry in the filterCache can occupy maxDoc/8 + some overhead
bytes. If maxDoc is very large, this’ll chew up an enormous amount of memory. I’m cheating
a bit here since the size might be smaller if only a few docs have any particular entry then the
size is smaller. But that’s the worst-case you have to allow for ‘cause you could theoretically hit
the perfect storm where, due to some particular sequence of queries, your entire filter
cache fills up with entries that size. 

You’ll have some overhead to keep the cache at that size, but it sounds like it’s worth it.

Best,
Erick



> On Jun 17, 2020, at 10:05 AM, James Bodkin <ja...@loveholidays.com> wrote:
> 
> The large majority of the relevant fields have fewer than 20 unique values. We have two fields over that with 150 unique values and 5300 unique values retrospectively.
> At the moment, our filterCache is configured with a maximum size of 8192.
> 
> From the DocValues documentation (https://lucene.apache.org/solr/guide/8_3/docvalues.html), it mentions that this approach promises to make lookups for faceting, sorting and grouping much faster.
> Hence I thought that using DocValues would be better than using Indexed and in turn improve our response times and possibly lower memory requirements. It sounds like this isn't the case if you are able to allocate enough memory to the filterCache.
> 
> I haven't yet tried changing the uninvertible setting, I was looking at the documentation for this field earlier today.
> Should we be setting uninvertible="false" if docValues="true" regardless of whether indexed is true or false?
> 
> Kind Regards,
> 
> James Bodkin
> 
> On 17/06/2020, 14:02, "Michael Gibney" <mi...@michaelgibney.net> wrote:
> 
>    facet.method=enum works by executing a query (against indexed values)
>    for each indexed value in a given field (which, for indexed=false, is
>    "no values"). So that explains why facet.method=enum no longer works.
>    I was going to suggest that you might not want to set indexed=false on
>    the docValues facet fields anyway, since the indexed values are still
>    used for facet refinement (assuming your index is distributed).
> 
>    What's the number of unique values in the relevant fields? If it's low
>    enough, setting docValues=false and indexed=true and using
>    facet.method=enum (with a sufficiently large filterCache) is
>    definitely a viable option, and will almost certainly be faster than
>    docValues-based faceting. (As an aside, noting for future reference:
>    high-cardinality facets over high-cardinality DocSet domains might be
>    able to benefit from a term facet count cache:
>    https://issues.apache.org/jira/browse/SOLR-13807)
> 
>    I think you didn't specifically mention whether you acted on Erick's
>    suggestion of setting "uninvertible=false" (I think Erick accidentally
>    said "uninvertible=true") to fail fast. I'd also recommend doing that,
>    perhaps even above all else -- it shouldn't actually *do* anything,
>    but will help ensure that things are behaving as you expect them to!
> 
>    Michael
> 
>    On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
>    <ja...@loveholidays.com> wrote:
>> 
>> Thanks, I've implemented some queries that improve the first-hit execution for faceting.
>> 
>> Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
>> Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
>> 
>> On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
>> 
>>    Ok, I see the disconnect... Necessary parts if the index are read from disk
>>    lazily. So your newSearcher or firstSearcher query needs to do whatever
>>    operation causes the relevant parts of the index to be read. In this case,
>>    probably just facet on all the fields you care about. I'd add sorting too
>>    if you sort on different fields.
>> 
>>    The *:* query without facets or sorting does virtually nothing due to some
>>    special handling...
>> 
>>    On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
>>    wrote:
>> 
>>> I've been trying to build a query that I can use in newSearcher based off
>>> the information in your previous e-mail. I thought you meant to build a *:*
>>> query as per Query 1 in my previous e-mail but I'm still seeing the
>>> first-hit execution.
>>> Now I'm wondering if you meant to create a *:* query with each of the
>>> fields as part of the fl query parameters or a *:* query with each of the
>>> fields and values as part of the fq query parameters.
>>> 
>>> At the moment I've been running these manually as I expected that I would
>>> see the first-execution penalty disappear by the time I got to query 4, as
>>> I thought this would replicate the actions of the newSeacher.
>>> Unfortunately we can't use the autowarm count that is available as part of
>>> the filterCache/filterCache due to the custom deployment mechanism we use
>>> to update our index.
>>> 
>>> Kind Regards,
>>> 
>>> James Bodkin
>>> 
>>> On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
>>> 
>>>    Did you try the autowarming like I mentioned in my previous e-mail?
>>> 
>>>> On Jun 16, 2020, at 10:18 AM, James Bodkin <
>>> james.bodkin@loveholidays.com> wrote:
>>>> 
>>>> We've changed the schema to enable docValues for these fields and
>>> this led to an improvement in the response time. We found a further
>>> improvement by also switching off indexed as these fields are used for
>>> faceting and filtering only.
>>>> Since those changes, we've found that the first-execution for
>>> queries is really noticeable. I thought this would be the filterCache based
>>> on what I saw in NewRelic however it is probably trying to read the
>>> docValues from disk. How can we use the autowarming to improve this?
>>>> 
>>>> For example, I've run the following queries in sequence and each
>>> query has a first-execution penalty.
>>>> 
>>>> Query 1:
>>>> 
>>>> q=*:*
>>>> facet=true
>>>> facet.field=D_DepartureAirport
>>>> facet.field=D_Destination
>>>> facet.limit=-1
>>>> rows=0
>>>> 
>>>> Query 2:
>>>> 
>>>> q=*:*
>>>> fq=D_DepartureAirport:(2660)
>>>> facet=true
>>>> facet.field=D_Destination
>>>> facet.limit=-1
>>>> rows=0
>>>> 
>>>> Query 3:
>>>> 
>>>> q=*:*
>>>> fq=D_DepartureAirport:(2661)
>>>> facet=true
>>>> facet.field=D_Destination
>>>> facet.limit=-1
>>>> rows=0
>>>> 
>>>> Query 4:
>>>> 
>>>> q=*:*
>>>> fq=D_DepartureAirport:(2660+OR+2661)
>>>> facet=true
>>>> facet.field=D_Destination
>>>> facet.limit=-1
>>>> rows=0
>>>> 
>>>> We've kept the field type as a string, as the value is mapped by
>>> application that accesses Solr. In the examples above, the values are
>>> mapped to airports and destinations.
>>>> Is it possible to prewarm the above queries without having to define
>>> all the potential filters manually in the auto warming?
>>>> 
>>>> At the moment, we update and optimise our index in a different
>>> environment and then copy the index to our production instances by using a
>>> rolling deployment in Kubernetes.
>>>> 
>>>> Kind Regards,
>>>> 
>>>> James Bodkin
>>>> 
>>>> On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
>>> wrote:
>>>> 
>>>>   I question whether fiterCache has anything to do with it, I
>>> suspect what’s really happening is that first time you’re reading the
>>> relevant bits from disk into memory. And to double check you should have
>>> docVaues enabled for all these fields. The “uninverting” process  can be
>>> very expensive, and docValues bypasses that.
>>>> 
>>>>   As of Solr 7.6, you can define “uninvertible=true” to your
>>> field(Type) to “fail fast” if Solr needs to uninvert the field.
>>>> 
>>>>   But that’s an aside. In either case, my claim is that first-time
>>> execution does “something”, either reads the serialized docValues from disk
>>> or uninverts the file on Solr’s heap.
>>>> 
>>>>   You can have this autowarmed by any combination of
>>>>   1> specifying an autowarm count on your queryResultCache. That’s
>>> hit or miss, as it replays the most recent N queries which may or may not
>>> contain the sorts. That said, specifying 10-20 for autowarm count is
>>> usually a good idea, assuming you’re not committing more than, say, every
>>> 30 seconds. I’d add the same to filterCache too.
>>>> 
>>>>   2> specifying a newSearcher or firstSearcher query in
>>> solrconfig.xml. The difference is that newSearcher is fired every time a
>>> commit happens, while firstSearcher is only fired when Solr starts, the
>>> theory being that there’s no cache autowarming available when Solr fist
>>> powers up. Usually, people don’t bother with firstSearcher or just make it
>>> the same as newSearcher. Note that a query doesn’t have to be “real” at
>>> all. You can just add all the facet fields to a *:* query in a single go.
>>>> 
>>>>   BTW, Trie fields will stay around for a long time even though
>>> deprecated. Or at least until we find something to replace them with that
>>> doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
>>> be more efficient than strings.
>>>> 
>>>>   Best,
>>>>   Erick
>>>> 
>>> 
>>> 


Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
The large majority of the relevant fields have fewer than 20 unique values. We have two fields over that with 150 unique values and 5300 unique values retrospectively.
At the moment, our filterCache is configured with a maximum size of 8192.

From the DocValues documentation (https://lucene.apache.org/solr/guide/8_3/docvalues.html), it mentions that this approach promises to make lookups for faceting, sorting and grouping much faster.
Hence I thought that using DocValues would be better than using Indexed and in turn improve our response times and possibly lower memory requirements. It sounds like this isn't the case if you are able to allocate enough memory to the filterCache.

I haven't yet tried changing the uninvertible setting, I was looking at the documentation for this field earlier today.
Should we be setting uninvertible="false" if docValues="true" regardless of whether indexed is true or false?

Kind Regards,

James Bodkin

On 17/06/2020, 14:02, "Michael Gibney" <mi...@michaelgibney.net> wrote:

    facet.method=enum works by executing a query (against indexed values)
    for each indexed value in a given field (which, for indexed=false, is
    "no values"). So that explains why facet.method=enum no longer works.
    I was going to suggest that you might not want to set indexed=false on
    the docValues facet fields anyway, since the indexed values are still
    used for facet refinement (assuming your index is distributed).

    What's the number of unique values in the relevant fields? If it's low
    enough, setting docValues=false and indexed=true and using
    facet.method=enum (with a sufficiently large filterCache) is
    definitely a viable option, and will almost certainly be faster than
    docValues-based faceting. (As an aside, noting for future reference:
    high-cardinality facets over high-cardinality DocSet domains might be
    able to benefit from a term facet count cache:
    https://issues.apache.org/jira/browse/SOLR-13807)

    I think you didn't specifically mention whether you acted on Erick's
    suggestion of setting "uninvertible=false" (I think Erick accidentally
    said "uninvertible=true") to fail fast. I'd also recommend doing that,
    perhaps even above all else -- it shouldn't actually *do* anything,
    but will help ensure that things are behaving as you expect them to!

    Michael

    On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
    <ja...@loveholidays.com> wrote:
    >
    > Thanks, I've implemented some queries that improve the first-hit execution for faceting.
    >
    > Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
    > Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
    >
    > On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
    >
    >     Ok, I see the disconnect... Necessary parts if the index are read from disk
    >     lazily. So your newSearcher or firstSearcher query needs to do whatever
    >     operation causes the relevant parts of the index to be read. In this case,
    >     probably just facet on all the fields you care about. I'd add sorting too
    >     if you sort on different fields.
    >
    >     The *:* query without facets or sorting does virtually nothing due to some
    >     special handling...
    >
    >     On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
    >     wrote:
    >
    >     > I've been trying to build a query that I can use in newSearcher based off
    >     > the information in your previous e-mail. I thought you meant to build a *:*
    >     > query as per Query 1 in my previous e-mail but I'm still seeing the
    >     > first-hit execution.
    >     > Now I'm wondering if you meant to create a *:* query with each of the
    >     > fields as part of the fl query parameters or a *:* query with each of the
    >     > fields and values as part of the fq query parameters.
    >     >
    >     > At the moment I've been running these manually as I expected that I would
    >     > see the first-execution penalty disappear by the time I got to query 4, as
    >     > I thought this would replicate the actions of the newSeacher.
    >     > Unfortunately we can't use the autowarm count that is available as part of
    >     > the filterCache/filterCache due to the custom deployment mechanism we use
    >     > to update our index.
    >     >
    >     > Kind Regards,
    >     >
    >     > James Bodkin
    >     >
    >     > On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
    >     >
    >     >     Did you try the autowarming like I mentioned in my previous e-mail?
    >     >
    >     >     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
    >     > james.bodkin@loveholidays.com> wrote:
    >     >     >
    >     >     > We've changed the schema to enable docValues for these fields and
    >     > this led to an improvement in the response time. We found a further
    >     > improvement by also switching off indexed as these fields are used for
    >     > faceting and filtering only.
    >     >     > Since those changes, we've found that the first-execution for
    >     > queries is really noticeable. I thought this would be the filterCache based
    >     > on what I saw in NewRelic however it is probably trying to read the
    >     > docValues from disk. How can we use the autowarming to improve this?
    >     >     >
    >     >     > For example, I've run the following queries in sequence and each
    >     > query has a first-execution penalty.
    >     >     >
    >     >     > Query 1:
    >     >     >
    >     >     > q=*:*
    >     >     > facet=true
    >     >     > facet.field=D_DepartureAirport
    >     >     > facet.field=D_Destination
    >     >     > facet.limit=-1
    >     >     > rows=0
    >     >     >
    >     >     > Query 2:
    >     >     >
    >     >     > q=*:*
    >     >     > fq=D_DepartureAirport:(2660)
    >     >     > facet=true
    >     >     > facet.field=D_Destination
    >     >     > facet.limit=-1
    >     >     > rows=0
    >     >     >
    >     >     > Query 3:
    >     >     >
    >     >     > q=*:*
    >     >     > fq=D_DepartureAirport:(2661)
    >     >     > facet=true
    >     >     > facet.field=D_Destination
    >     >     > facet.limit=-1
    >     >     > rows=0
    >     >     >
    >     >     > Query 4:
    >     >     >
    >     >     > q=*:*
    >     >     > fq=D_DepartureAirport:(2660+OR+2661)
    >     >     > facet=true
    >     >     > facet.field=D_Destination
    >     >     > facet.limit=-1
    >     >     > rows=0
    >     >     >
    >     >     > We've kept the field type as a string, as the value is mapped by
    >     > application that accesses Solr. In the examples above, the values are
    >     > mapped to airports and destinations.
    >     >     > Is it possible to prewarm the above queries without having to define
    >     > all the potential filters manually in the auto warming?
    >     >     >
    >     >     > At the moment, we update and optimise our index in a different
    >     > environment and then copy the index to our production instances by using a
    >     > rolling deployment in Kubernetes.
    >     >     >
    >     >     > Kind Regards,
    >     >     >
    >     >     > James Bodkin
    >     >     >
    >     >     > On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
    >     > wrote:
    >     >     >
    >     >     >    I question whether fiterCache has anything to do with it, I
    >     > suspect what’s really happening is that first time you’re reading the
    >     > relevant bits from disk into memory. And to double check you should have
    >     > docVaues enabled for all these fields. The “uninverting” process  can be
    >     > very expensive, and docValues bypasses that.
    >     >     >
    >     >     >    As of Solr 7.6, you can define “uninvertible=true” to your
    >     > field(Type) to “fail fast” if Solr needs to uninvert the field.
    >     >     >
    >     >     >    But that’s an aside. In either case, my claim is that first-time
    >     > execution does “something”, either reads the serialized docValues from disk
    >     > or uninverts the file on Solr’s heap.
    >     >     >
    >     >     >    You can have this autowarmed by any combination of
    >     >     >    1> specifying an autowarm count on your queryResultCache. That’s
    >     > hit or miss, as it replays the most recent N queries which may or may not
    >     > contain the sorts. That said, specifying 10-20 for autowarm count is
    >     > usually a good idea, assuming you’re not committing more than, say, every
    >     > 30 seconds. I’d add the same to filterCache too.
    >     >     >
    >     >     >    2> specifying a newSearcher or firstSearcher query in
    >     > solrconfig.xml. The difference is that newSearcher is fired every time a
    >     > commit happens, while firstSearcher is only fired when Solr starts, the
    >     > theory being that there’s no cache autowarming available when Solr fist
    >     > powers up. Usually, people don’t bother with firstSearcher or just make it
    >     > the same as newSearcher. Note that a query doesn’t have to be “real” at
    >     > all. You can just add all the facet fields to a *:* query in a single go.
    >     >     >
    >     >     >    BTW, Trie fields will stay around for a long time even though
    >     > deprecated. Or at least until we find something to replace them with that
    >     > doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
    >     > be more efficient than strings.
    >     >     >
    >     >     >    Best,
    >     >     >    Erick
    >     >     >
    >     >
    >     >

Re: Facet Performance

Posted by Anthony Groves <ag...@oreilly.com>.
Ah, interesting! So if the number of possible values is low (like <= 10),
it is faster to *not *use docvalues on that (indexed) faceted field?
Does this hold true even when using faceting techniques like tag and
exclusion?

Thanks,
Anthony


On Wed, Jun 17, 2020 at 9:37 AM David Smiley <da...@gmail.com>
wrote:

> I strongly recommend setting indexed=true on a field you facet on for the
> purposes of efficient refinement (fq=field:value).  But it strictly isn't
> required, as you have discovered.
>
> ~ David
>
>
> On Wed, Jun 17, 2020 at 9:02 AM Michael Gibney <mi...@michaelgibney.net>
> wrote:
>
> > facet.method=enum works by executing a query (against indexed values)
> > for each indexed value in a given field (which, for indexed=false, is
> > "no values"). So that explains why facet.method=enum no longer works.
> > I was going to suggest that you might not want to set indexed=false on
> > the docValues facet fields anyway, since the indexed values are still
> > used for facet refinement (assuming your index is distributed).
> >
> > What's the number of unique values in the relevant fields? If it's low
> > enough, setting docValues=false and indexed=true and using
> > facet.method=enum (with a sufficiently large filterCache) is
> > definitely a viable option, and will almost certainly be faster than
> > docValues-based faceting. (As an aside, noting for future reference:
> > high-cardinality facets over high-cardinality DocSet domains might be
> > able to benefit from a term facet count cache:
> > https://issues.apache.org/jira/browse/SOLR-13807)
> >
> > I think you didn't specifically mention whether you acted on Erick's
> > suggestion of setting "uninvertible=false" (I think Erick accidentally
> > said "uninvertible=true") to fail fast. I'd also recommend doing that,
> > perhaps even above all else -- it shouldn't actually *do* anything,
> > but will help ensure that things are behaving as you expect them to!
> >
> > Michael
> >
> > On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
> > <ja...@loveholidays.com> wrote:
> > >
> > > Thanks, I've implemented some queries that improve the first-hit
> > execution for faceting.
> > >
> > > Since turning off indexed on those fields, we've noticed that
> > facet.method=enum no longer returns the facets when used.
> > > Using facet.method=fc/fcs is significantly slower compared to
> > facet.method=enum for us. Why do these two differences exist?
> > >
> > > On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com>
> wrote:
> > >
> > >     Ok, I see the disconnect... Necessary parts if the index are read
> > from disk
> > >     lazily. So your newSearcher or firstSearcher query needs to do
> > whatever
> > >     operation causes the relevant parts of the index to be read. In
> this
> > case,
> > >     probably just facet on all the fields you care about. I'd add
> > sorting too
> > >     if you sort on different fields.
> > >
> > >     The *:* query without facets or sorting does virtually nothing due
> > to some
> > >     special handling...
> > >
> > >     On Tue, Jun 16, 2020, 10:48 James Bodkin <
> > james.bodkin@loveholidays.com>
> > >     wrote:
> > >
> > >     > I've been trying to build a query that I can use in newSearcher
> > based off
> > >     > the information in your previous e-mail. I thought you meant to
> > build a *:*
> > >     > query as per Query 1 in my previous e-mail but I'm still seeing
> the
> > >     > first-hit execution.
> > >     > Now I'm wondering if you meant to create a *:* query with each of
> > the
> > >     > fields as part of the fl query parameters or a *:* query with
> each
> > of the
> > >     > fields and values as part of the fq query parameters.
> > >     >
> > >     > At the moment I've been running these manually as I expected that
> > I would
> > >     > see the first-execution penalty disappear by the time I got to
> > query 4, as
> > >     > I thought this would replicate the actions of the newSeacher.
> > >     > Unfortunately we can't use the autowarm count that is available
> as
> > part of
> > >     > the filterCache/filterCache due to the custom deployment
> mechanism
> > we use
> > >     > to update our index.
> > >     >
> > >     > Kind Regards,
> > >     >
> > >     > James Bodkin
> > >     >
> > >     > On 16/06/2020, 15:30, "Erick Erickson" <erickerickson@gmail.com
> >
> > wrote:
> > >     >
> > >     >     Did you try the autowarming like I mentioned in my previous
> > e-mail?
> > >     >
> > >     >     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
> > >     > james.bodkin@loveholidays.com> wrote:
> > >     >     >
> > >     >     > We've changed the schema to enable docValues for these
> > fields and
> > >     > this led to an improvement in the response time. We found a
> further
> > >     > improvement by also switching off indexed as these fields are
> used
> > for
> > >     > faceting and filtering only.
> > >     >     > Since those changes, we've found that the first-execution
> for
> > >     > queries is really noticeable. I thought this would be the
> > filterCache based
> > >     > on what I saw in NewRelic however it is probably trying to read
> the
> > >     > docValues from disk. How can we use the autowarming to improve
> > this?
> > >     >     >
> > >     >     > For example, I've run the following queries in sequence and
> > each
> > >     > query has a first-execution penalty.
> > >     >     >
> > >     >     > Query 1:
> > >     >     >
> > >     >     > q=*:*
> > >     >     > facet=true
> > >     >     > facet.field=D_DepartureAirport
> > >     >     > facet.field=D_Destination
> > >     >     > facet.limit=-1
> > >     >     > rows=0
> > >     >     >
> > >     >     > Query 2:
> > >     >     >
> > >     >     > q=*:*
> > >     >     > fq=D_DepartureAirport:(2660)
> > >     >     > facet=true
> > >     >     > facet.field=D_Destination
> > >     >     > facet.limit=-1
> > >     >     > rows=0
> > >     >     >
> > >     >     > Query 3:
> > >     >     >
> > >     >     > q=*:*
> > >     >     > fq=D_DepartureAirport:(2661)
> > >     >     > facet=true
> > >     >     > facet.field=D_Destination
> > >     >     > facet.limit=-1
> > >     >     > rows=0
> > >     >     >
> > >     >     > Query 4:
> > >     >     >
> > >     >     > q=*:*
> > >     >     > fq=D_DepartureAirport:(2660+OR+2661)
> > >     >     > facet=true
> > >     >     > facet.field=D_Destination
> > >     >     > facet.limit=-1
> > >     >     > rows=0
> > >     >     >
> > >     >     > We've kept the field type as a string, as the value is
> > mapped by
> > >     > application that accesses Solr. In the examples above, the values
> > are
> > >     > mapped to airports and destinations.
> > >     >     > Is it possible to prewarm the above queries without having
> > to define
> > >     > all the potential filters manually in the auto warming?
> > >     >     >
> > >     >     > At the moment, we update and optimise our index in a
> > different
> > >     > environment and then copy the index to our production instances
> by
> > using a
> > >     > rolling deployment in Kubernetes.
> > >     >     >
> > >     >     > Kind Regards,
> > >     >     >
> > >     >     > James Bodkin
> > >     >     >
> > >     >     > On 12/06/2020, 18:58, "Erick Erickson" <
> > erickerickson@gmail.com>
> > >     > wrote:
> > >     >     >
> > >     >     >    I question whether fiterCache has anything to do with
> it,
> > I
> > >     > suspect what’s really happening is that first time you’re reading
> > the
> > >     > relevant bits from disk into memory. And to double check you
> > should have
> > >     > docVaues enabled for all these fields. The “uninverting” process
> > can be
> > >     > very expensive, and docValues bypasses that.
> > >     >     >
> > >     >     >    As of Solr 7.6, you can define “uninvertible=true” to
> your
> > >     > field(Type) to “fail fast” if Solr needs to uninvert the field.
> > >     >     >
> > >     >     >    But that’s an aside. In either case, my claim is that
> > first-time
> > >     > execution does “something”, either reads the serialized docValues
> > from disk
> > >     > or uninverts the file on Solr’s heap.
> > >     >     >
> > >     >     >    You can have this autowarmed by any combination of
> > >     >     >    1> specifying an autowarm count on your
> queryResultCache.
> > That’s
> > >     > hit or miss, as it replays the most recent N queries which may or
> > may not
> > >     > contain the sorts. That said, specifying 10-20 for autowarm count
> > is
> > >     > usually a good idea, assuming you’re not committing more than,
> > say, every
> > >     > 30 seconds. I’d add the same to filterCache too.
> > >     >     >
> > >     >     >    2> specifying a newSearcher or firstSearcher query in
> > >     > solrconfig.xml. The difference is that newSearcher is fired every
> > time a
> > >     > commit happens, while firstSearcher is only fired when Solr
> > starts, the
> > >     > theory being that there’s no cache autowarming available when
> Solr
> > fist
> > >     > powers up. Usually, people don’t bother with firstSearcher or
> just
> > make it
> > >     > the same as newSearcher. Note that a query doesn’t have to be
> > “real” at
> > >     > all. You can just add all the facet fields to a *:* query in a
> > single go.
> > >     >     >
> > >     >     >    BTW, Trie fields will stay around for a long time even
> > though
> > >     > deprecated. Or at least until we find something to replace them
> > with that
> > >     > doesn’t have this penalty, so I’d feel pretty safe using those
> and
> > they’ll
> > >     > be more efficient than strings.
> > >     >     >
> > >     >     >    Best,
> > >     >     >    Erick
> > >     >     >
> > >     >
> > >     >
> >
>

Re: Facet Performance

Posted by David Smiley <da...@gmail.com>.
I strongly recommend setting indexed=true on a field you facet on for the
purposes of efficient refinement (fq=field:value).  But it strictly isn't
required, as you have discovered.

~ David


On Wed, Jun 17, 2020 at 9:02 AM Michael Gibney <mi...@michaelgibney.net>
wrote:

> facet.method=enum works by executing a query (against indexed values)
> for each indexed value in a given field (which, for indexed=false, is
> "no values"). So that explains why facet.method=enum no longer works.
> I was going to suggest that you might not want to set indexed=false on
> the docValues facet fields anyway, since the indexed values are still
> used for facet refinement (assuming your index is distributed).
>
> What's the number of unique values in the relevant fields? If it's low
> enough, setting docValues=false and indexed=true and using
> facet.method=enum (with a sufficiently large filterCache) is
> definitely a viable option, and will almost certainly be faster than
> docValues-based faceting. (As an aside, noting for future reference:
> high-cardinality facets over high-cardinality DocSet domains might be
> able to benefit from a term facet count cache:
> https://issues.apache.org/jira/browse/SOLR-13807)
>
> I think you didn't specifically mention whether you acted on Erick's
> suggestion of setting "uninvertible=false" (I think Erick accidentally
> said "uninvertible=true") to fail fast. I'd also recommend doing that,
> perhaps even above all else -- it shouldn't actually *do* anything,
> but will help ensure that things are behaving as you expect them to!
>
> Michael
>
> On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
> <ja...@loveholidays.com> wrote:
> >
> > Thanks, I've implemented some queries that improve the first-hit
> execution for faceting.
> >
> > Since turning off indexed on those fields, we've noticed that
> facet.method=enum no longer returns the facets when used.
> > Using facet.method=fc/fcs is significantly slower compared to
> facet.method=enum for us. Why do these two differences exist?
> >
> > On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
> >
> >     Ok, I see the disconnect... Necessary parts if the index are read
> from disk
> >     lazily. So your newSearcher or firstSearcher query needs to do
> whatever
> >     operation causes the relevant parts of the index to be read. In this
> case,
> >     probably just facet on all the fields you care about. I'd add
> sorting too
> >     if you sort on different fields.
> >
> >     The *:* query without facets or sorting does virtually nothing due
> to some
> >     special handling...
> >
> >     On Tue, Jun 16, 2020, 10:48 James Bodkin <
> james.bodkin@loveholidays.com>
> >     wrote:
> >
> >     > I've been trying to build a query that I can use in newSearcher
> based off
> >     > the information in your previous e-mail. I thought you meant to
> build a *:*
> >     > query as per Query 1 in my previous e-mail but I'm still seeing the
> >     > first-hit execution.
> >     > Now I'm wondering if you meant to create a *:* query with each of
> the
> >     > fields as part of the fl query parameters or a *:* query with each
> of the
> >     > fields and values as part of the fq query parameters.
> >     >
> >     > At the moment I've been running these manually as I expected that
> I would
> >     > see the first-execution penalty disappear by the time I got to
> query 4, as
> >     > I thought this would replicate the actions of the newSeacher.
> >     > Unfortunately we can't use the autowarm count that is available as
> part of
> >     > the filterCache/filterCache due to the custom deployment mechanism
> we use
> >     > to update our index.
> >     >
> >     > Kind Regards,
> >     >
> >     > James Bodkin
> >     >
> >     > On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com>
> wrote:
> >     >
> >     >     Did you try the autowarming like I mentioned in my previous
> e-mail?
> >     >
> >     >     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
> >     > james.bodkin@loveholidays.com> wrote:
> >     >     >
> >     >     > We've changed the schema to enable docValues for these
> fields and
> >     > this led to an improvement in the response time. We found a further
> >     > improvement by also switching off indexed as these fields are used
> for
> >     > faceting and filtering only.
> >     >     > Since those changes, we've found that the first-execution for
> >     > queries is really noticeable. I thought this would be the
> filterCache based
> >     > on what I saw in NewRelic however it is probably trying to read the
> >     > docValues from disk. How can we use the autowarming to improve
> this?
> >     >     >
> >     >     > For example, I've run the following queries in sequence and
> each
> >     > query has a first-execution penalty.
> >     >     >
> >     >     > Query 1:
> >     >     >
> >     >     > q=*:*
> >     >     > facet=true
> >     >     > facet.field=D_DepartureAirport
> >     >     > facet.field=D_Destination
> >     >     > facet.limit=-1
> >     >     > rows=0
> >     >     >
> >     >     > Query 2:
> >     >     >
> >     >     > q=*:*
> >     >     > fq=D_DepartureAirport:(2660)
> >     >     > facet=true
> >     >     > facet.field=D_Destination
> >     >     > facet.limit=-1
> >     >     > rows=0
> >     >     >
> >     >     > Query 3:
> >     >     >
> >     >     > q=*:*
> >     >     > fq=D_DepartureAirport:(2661)
> >     >     > facet=true
> >     >     > facet.field=D_Destination
> >     >     > facet.limit=-1
> >     >     > rows=0
> >     >     >
> >     >     > Query 4:
> >     >     >
> >     >     > q=*:*
> >     >     > fq=D_DepartureAirport:(2660+OR+2661)
> >     >     > facet=true
> >     >     > facet.field=D_Destination
> >     >     > facet.limit=-1
> >     >     > rows=0
> >     >     >
> >     >     > We've kept the field type as a string, as the value is
> mapped by
> >     > application that accesses Solr. In the examples above, the values
> are
> >     > mapped to airports and destinations.
> >     >     > Is it possible to prewarm the above queries without having
> to define
> >     > all the potential filters manually in the auto warming?
> >     >     >
> >     >     > At the moment, we update and optimise our index in a
> different
> >     > environment and then copy the index to our production instances by
> using a
> >     > rolling deployment in Kubernetes.
> >     >     >
> >     >     > Kind Regards,
> >     >     >
> >     >     > James Bodkin
> >     >     >
> >     >     > On 12/06/2020, 18:58, "Erick Erickson" <
> erickerickson@gmail.com>
> >     > wrote:
> >     >     >
> >     >     >    I question whether fiterCache has anything to do with it,
> I
> >     > suspect what’s really happening is that first time you’re reading
> the
> >     > relevant bits from disk into memory. And to double check you
> should have
> >     > docVaues enabled for all these fields. The “uninverting” process
> can be
> >     > very expensive, and docValues bypasses that.
> >     >     >
> >     >     >    As of Solr 7.6, you can define “uninvertible=true” to your
> >     > field(Type) to “fail fast” if Solr needs to uninvert the field.
> >     >     >
> >     >     >    But that’s an aside. In either case, my claim is that
> first-time
> >     > execution does “something”, either reads the serialized docValues
> from disk
> >     > or uninverts the file on Solr’s heap.
> >     >     >
> >     >     >    You can have this autowarmed by any combination of
> >     >     >    1> specifying an autowarm count on your queryResultCache.
> That’s
> >     > hit or miss, as it replays the most recent N queries which may or
> may not
> >     > contain the sorts. That said, specifying 10-20 for autowarm count
> is
> >     > usually a good idea, assuming you’re not committing more than,
> say, every
> >     > 30 seconds. I’d add the same to filterCache too.
> >     >     >
> >     >     >    2> specifying a newSearcher or firstSearcher query in
> >     > solrconfig.xml. The difference is that newSearcher is fired every
> time a
> >     > commit happens, while firstSearcher is only fired when Solr
> starts, the
> >     > theory being that there’s no cache autowarming available when Solr
> fist
> >     > powers up. Usually, people don’t bother with firstSearcher or just
> make it
> >     > the same as newSearcher. Note that a query doesn’t have to be
> “real” at
> >     > all. You can just add all the facet fields to a *:* query in a
> single go.
> >     >     >
> >     >     >    BTW, Trie fields will stay around for a long time even
> though
> >     > deprecated. Or at least until we find something to replace them
> with that
> >     > doesn’t have this penalty, so I’d feel pretty safe using those and
> they’ll
> >     > be more efficient than strings.
> >     >     >
> >     >     >    Best,
> >     >     >    Erick
> >     >     >
> >     >
> >     >
>

Re: Facet Performance

Posted by Michael Gibney <mi...@michaelgibney.net>.
facet.method=enum works by executing a query (against indexed values)
for each indexed value in a given field (which, for indexed=false, is
"no values"). So that explains why facet.method=enum no longer works.
I was going to suggest that you might not want to set indexed=false on
the docValues facet fields anyway, since the indexed values are still
used for facet refinement (assuming your index is distributed).

What's the number of unique values in the relevant fields? If it's low
enough, setting docValues=false and indexed=true and using
facet.method=enum (with a sufficiently large filterCache) is
definitely a viable option, and will almost certainly be faster than
docValues-based faceting. (As an aside, noting for future reference:
high-cardinality facets over high-cardinality DocSet domains might be
able to benefit from a term facet count cache:
https://issues.apache.org/jira/browse/SOLR-13807)

I think you didn't specifically mention whether you acted on Erick's
suggestion of setting "uninvertible=false" (I think Erick accidentally
said "uninvertible=true") to fail fast. I'd also recommend doing that,
perhaps even above all else -- it shouldn't actually *do* anything,
but will help ensure that things are behaving as you expect them to!

Michael

On Wed, Jun 17, 2020 at 4:31 AM James Bodkin
<ja...@loveholidays.com> wrote:
>
> Thanks, I've implemented some queries that improve the first-hit execution for faceting.
>
> Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
> Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?
>
> On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:
>
>     Ok, I see the disconnect... Necessary parts if the index are read from disk
>     lazily. So your newSearcher or firstSearcher query needs to do whatever
>     operation causes the relevant parts of the index to be read. In this case,
>     probably just facet on all the fields you care about. I'd add sorting too
>     if you sort on different fields.
>
>     The *:* query without facets or sorting does virtually nothing due to some
>     special handling...
>
>     On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
>     wrote:
>
>     > I've been trying to build a query that I can use in newSearcher based off
>     > the information in your previous e-mail. I thought you meant to build a *:*
>     > query as per Query 1 in my previous e-mail but I'm still seeing the
>     > first-hit execution.
>     > Now I'm wondering if you meant to create a *:* query with each of the
>     > fields as part of the fl query parameters or a *:* query with each of the
>     > fields and values as part of the fq query parameters.
>     >
>     > At the moment I've been running these manually as I expected that I would
>     > see the first-execution penalty disappear by the time I got to query 4, as
>     > I thought this would replicate the actions of the newSeacher.
>     > Unfortunately we can't use the autowarm count that is available as part of
>     > the filterCache/filterCache due to the custom deployment mechanism we use
>     > to update our index.
>     >
>     > Kind Regards,
>     >
>     > James Bodkin
>     >
>     > On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
>     >
>     >     Did you try the autowarming like I mentioned in my previous e-mail?
>     >
>     >     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
>     > james.bodkin@loveholidays.com> wrote:
>     >     >
>     >     > We've changed the schema to enable docValues for these fields and
>     > this led to an improvement in the response time. We found a further
>     > improvement by also switching off indexed as these fields are used for
>     > faceting and filtering only.
>     >     > Since those changes, we've found that the first-execution for
>     > queries is really noticeable. I thought this would be the filterCache based
>     > on what I saw in NewRelic however it is probably trying to read the
>     > docValues from disk. How can we use the autowarming to improve this?
>     >     >
>     >     > For example, I've run the following queries in sequence and each
>     > query has a first-execution penalty.
>     >     >
>     >     > Query 1:
>     >     >
>     >     > q=*:*
>     >     > facet=true
>     >     > facet.field=D_DepartureAirport
>     >     > facet.field=D_Destination
>     >     > facet.limit=-1
>     >     > rows=0
>     >     >
>     >     > Query 2:
>     >     >
>     >     > q=*:*
>     >     > fq=D_DepartureAirport:(2660)
>     >     > facet=true
>     >     > facet.field=D_Destination
>     >     > facet.limit=-1
>     >     > rows=0
>     >     >
>     >     > Query 3:
>     >     >
>     >     > q=*:*
>     >     > fq=D_DepartureAirport:(2661)
>     >     > facet=true
>     >     > facet.field=D_Destination
>     >     > facet.limit=-1
>     >     > rows=0
>     >     >
>     >     > Query 4:
>     >     >
>     >     > q=*:*
>     >     > fq=D_DepartureAirport:(2660+OR+2661)
>     >     > facet=true
>     >     > facet.field=D_Destination
>     >     > facet.limit=-1
>     >     > rows=0
>     >     >
>     >     > We've kept the field type as a string, as the value is mapped by
>     > application that accesses Solr. In the examples above, the values are
>     > mapped to airports and destinations.
>     >     > Is it possible to prewarm the above queries without having to define
>     > all the potential filters manually in the auto warming?
>     >     >
>     >     > At the moment, we update and optimise our index in a different
>     > environment and then copy the index to our production instances by using a
>     > rolling deployment in Kubernetes.
>     >     >
>     >     > Kind Regards,
>     >     >
>     >     > James Bodkin
>     >     >
>     >     > On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
>     > wrote:
>     >     >
>     >     >    I question whether fiterCache has anything to do with it, I
>     > suspect what’s really happening is that first time you’re reading the
>     > relevant bits from disk into memory. And to double check you should have
>     > docVaues enabled for all these fields. The “uninverting” process  can be
>     > very expensive, and docValues bypasses that.
>     >     >
>     >     >    As of Solr 7.6, you can define “uninvertible=true” to your
>     > field(Type) to “fail fast” if Solr needs to uninvert the field.
>     >     >
>     >     >    But that’s an aside. In either case, my claim is that first-time
>     > execution does “something”, either reads the serialized docValues from disk
>     > or uninverts the file on Solr’s heap.
>     >     >
>     >     >    You can have this autowarmed by any combination of
>     >     >    1> specifying an autowarm count on your queryResultCache. That’s
>     > hit or miss, as it replays the most recent N queries which may or may not
>     > contain the sorts. That said, specifying 10-20 for autowarm count is
>     > usually a good idea, assuming you’re not committing more than, say, every
>     > 30 seconds. I’d add the same to filterCache too.
>     >     >
>     >     >    2> specifying a newSearcher or firstSearcher query in
>     > solrconfig.xml. The difference is that newSearcher is fired every time a
>     > commit happens, while firstSearcher is only fired when Solr starts, the
>     > theory being that there’s no cache autowarming available when Solr fist
>     > powers up. Usually, people don’t bother with firstSearcher or just make it
>     > the same as newSearcher. Note that a query doesn’t have to be “real” at
>     > all. You can just add all the facet fields to a *:* query in a single go.
>     >     >
>     >     >    BTW, Trie fields will stay around for a long time even though
>     > deprecated. Or at least until we find something to replace them with that
>     > doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
>     > be more efficient than strings.
>     >     >
>     >     >    Best,
>     >     >    Erick
>     >     >
>     >
>     >

Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
Thanks, I've implemented some queries that improve the first-hit execution for faceting.

Since turning off indexed on those fields, we've noticed that facet.method=enum no longer returns the facets when used.
Using facet.method=fc/fcs is significantly slower compared to facet.method=enum for us. Why do these two differences exist?

On 16/06/2020, 17:52, "Erick Erickson" <er...@gmail.com> wrote:

    Ok, I see the disconnect... Necessary parts if the index are read from disk
    lazily. So your newSearcher or firstSearcher query needs to do whatever
    operation causes the relevant parts of the index to be read. In this case,
    probably just facet on all the fields you care about. I'd add sorting too
    if you sort on different fields.

    The *:* query without facets or sorting does virtually nothing due to some
    special handling...

    On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
    wrote:

    > I've been trying to build a query that I can use in newSearcher based off
    > the information in your previous e-mail. I thought you meant to build a *:*
    > query as per Query 1 in my previous e-mail but I'm still seeing the
    > first-hit execution.
    > Now I'm wondering if you meant to create a *:* query with each of the
    > fields as part of the fl query parameters or a *:* query with each of the
    > fields and values as part of the fq query parameters.
    >
    > At the moment I've been running these manually as I expected that I would
    > see the first-execution penalty disappear by the time I got to query 4, as
    > I thought this would replicate the actions of the newSeacher.
    > Unfortunately we can't use the autowarm count that is available as part of
    > the filterCache/filterCache due to the custom deployment mechanism we use
    > to update our index.
    >
    > Kind Regards,
    >
    > James Bodkin
    >
    > On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
    >
    >     Did you try the autowarming like I mentioned in my previous e-mail?
    >
    >     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
    > james.bodkin@loveholidays.com> wrote:
    >     >
    >     > We've changed the schema to enable docValues for these fields and
    > this led to an improvement in the response time. We found a further
    > improvement by also switching off indexed as these fields are used for
    > faceting and filtering only.
    >     > Since those changes, we've found that the first-execution for
    > queries is really noticeable. I thought this would be the filterCache based
    > on what I saw in NewRelic however it is probably trying to read the
    > docValues from disk. How can we use the autowarming to improve this?
    >     >
    >     > For example, I've run the following queries in sequence and each
    > query has a first-execution penalty.
    >     >
    >     > Query 1:
    >     >
    >     > q=*:*
    >     > facet=true
    >     > facet.field=D_DepartureAirport
    >     > facet.field=D_Destination
    >     > facet.limit=-1
    >     > rows=0
    >     >
    >     > Query 2:
    >     >
    >     > q=*:*
    >     > fq=D_DepartureAirport:(2660)
    >     > facet=true
    >     > facet.field=D_Destination
    >     > facet.limit=-1
    >     > rows=0
    >     >
    >     > Query 3:
    >     >
    >     > q=*:*
    >     > fq=D_DepartureAirport:(2661)
    >     > facet=true
    >     > facet.field=D_Destination
    >     > facet.limit=-1
    >     > rows=0
    >     >
    >     > Query 4:
    >     >
    >     > q=*:*
    >     > fq=D_DepartureAirport:(2660+OR+2661)
    >     > facet=true
    >     > facet.field=D_Destination
    >     > facet.limit=-1
    >     > rows=0
    >     >
    >     > We've kept the field type as a string, as the value is mapped by
    > application that accesses Solr. In the examples above, the values are
    > mapped to airports and destinations.
    >     > Is it possible to prewarm the above queries without having to define
    > all the potential filters manually in the auto warming?
    >     >
    >     > At the moment, we update and optimise our index in a different
    > environment and then copy the index to our production instances by using a
    > rolling deployment in Kubernetes.
    >     >
    >     > Kind Regards,
    >     >
    >     > James Bodkin
    >     >
    >     > On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
    > wrote:
    >     >
    >     >    I question whether fiterCache has anything to do with it, I
    > suspect what’s really happening is that first time you’re reading the
    > relevant bits from disk into memory. And to double check you should have
    > docVaues enabled for all these fields. The “uninverting” process  can be
    > very expensive, and docValues bypasses that.
    >     >
    >     >    As of Solr 7.6, you can define “uninvertible=true” to your
    > field(Type) to “fail fast” if Solr needs to uninvert the field.
    >     >
    >     >    But that’s an aside. In either case, my claim is that first-time
    > execution does “something”, either reads the serialized docValues from disk
    > or uninverts the file on Solr’s heap.
    >     >
    >     >    You can have this autowarmed by any combination of
    >     >    1> specifying an autowarm count on your queryResultCache. That’s
    > hit or miss, as it replays the most recent N queries which may or may not
    > contain the sorts. That said, specifying 10-20 for autowarm count is
    > usually a good idea, assuming you’re not committing more than, say, every
    > 30 seconds. I’d add the same to filterCache too.
    >     >
    >     >    2> specifying a newSearcher or firstSearcher query in
    > solrconfig.xml. The difference is that newSearcher is fired every time a
    > commit happens, while firstSearcher is only fired when Solr starts, the
    > theory being that there’s no cache autowarming available when Solr fist
    > powers up. Usually, people don’t bother with firstSearcher or just make it
    > the same as newSearcher. Note that a query doesn’t have to be “real” at
    > all. You can just add all the facet fields to a *:* query in a single go.
    >     >
    >     >    BTW, Trie fields will stay around for a long time even though
    > deprecated. Or at least until we find something to replace them with that
    > doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
    > be more efficient than strings.
    >     >
    >     >    Best,
    >     >    Erick
    >     >
    >
    >

Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
Ok, I see the disconnect... Necessary parts if the index are read from disk
lazily. So your newSearcher or firstSearcher query needs to do whatever
operation causes the relevant parts of the index to be read. In this case,
probably just facet on all the fields you care about. I'd add sorting too
if you sort on different fields.

The *:* query without facets or sorting does virtually nothing due to some
special handling...

On Tue, Jun 16, 2020, 10:48 James Bodkin <ja...@loveholidays.com>
wrote:

> I've been trying to build a query that I can use in newSearcher based off
> the information in your previous e-mail. I thought you meant to build a *:*
> query as per Query 1 in my previous e-mail but I'm still seeing the
> first-hit execution.
> Now I'm wondering if you meant to create a *:* query with each of the
> fields as part of the fl query parameters or a *:* query with each of the
> fields and values as part of the fq query parameters.
>
> At the moment I've been running these manually as I expected that I would
> see the first-execution penalty disappear by the time I got to query 4, as
> I thought this would replicate the actions of the newSeacher.
> Unfortunately we can't use the autowarm count that is available as part of
> the filterCache/filterCache due to the custom deployment mechanism we use
> to update our index.
>
> Kind Regards,
>
> James Bodkin
>
> On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:
>
>     Did you try the autowarming like I mentioned in my previous e-mail?
>
>     > On Jun 16, 2020, at 10:18 AM, James Bodkin <
> james.bodkin@loveholidays.com> wrote:
>     >
>     > We've changed the schema to enable docValues for these fields and
> this led to an improvement in the response time. We found a further
> improvement by also switching off indexed as these fields are used for
> faceting and filtering only.
>     > Since those changes, we've found that the first-execution for
> queries is really noticeable. I thought this would be the filterCache based
> on what I saw in NewRelic however it is probably trying to read the
> docValues from disk. How can we use the autowarming to improve this?
>     >
>     > For example, I've run the following queries in sequence and each
> query has a first-execution penalty.
>     >
>     > Query 1:
>     >
>     > q=*:*
>     > facet=true
>     > facet.field=D_DepartureAirport
>     > facet.field=D_Destination
>     > facet.limit=-1
>     > rows=0
>     >
>     > Query 2:
>     >
>     > q=*:*
>     > fq=D_DepartureAirport:(2660)
>     > facet=true
>     > facet.field=D_Destination
>     > facet.limit=-1
>     > rows=0
>     >
>     > Query 3:
>     >
>     > q=*:*
>     > fq=D_DepartureAirport:(2661)
>     > facet=true
>     > facet.field=D_Destination
>     > facet.limit=-1
>     > rows=0
>     >
>     > Query 4:
>     >
>     > q=*:*
>     > fq=D_DepartureAirport:(2660+OR+2661)
>     > facet=true
>     > facet.field=D_Destination
>     > facet.limit=-1
>     > rows=0
>     >
>     > We've kept the field type as a string, as the value is mapped by
> application that accesses Solr. In the examples above, the values are
> mapped to airports and destinations.
>     > Is it possible to prewarm the above queries without having to define
> all the potential filters manually in the auto warming?
>     >
>     > At the moment, we update and optimise our index in a different
> environment and then copy the index to our production instances by using a
> rolling deployment in Kubernetes.
>     >
>     > Kind Regards,
>     >
>     > James Bodkin
>     >
>     > On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com>
> wrote:
>     >
>     >    I question whether fiterCache has anything to do with it, I
> suspect what’s really happening is that first time you’re reading the
> relevant bits from disk into memory. And to double check you should have
> docVaues enabled for all these fields. The “uninverting” process  can be
> very expensive, and docValues bypasses that.
>     >
>     >    As of Solr 7.6, you can define “uninvertible=true” to your
> field(Type) to “fail fast” if Solr needs to uninvert the field.
>     >
>     >    But that’s an aside. In either case, my claim is that first-time
> execution does “something”, either reads the serialized docValues from disk
> or uninverts the file on Solr’s heap.
>     >
>     >    You can have this autowarmed by any combination of
>     >    1> specifying an autowarm count on your queryResultCache. That’s
> hit or miss, as it replays the most recent N queries which may or may not
> contain the sorts. That said, specifying 10-20 for autowarm count is
> usually a good idea, assuming you’re not committing more than, say, every
> 30 seconds. I’d add the same to filterCache too.
>     >
>     >    2> specifying a newSearcher or firstSearcher query in
> solrconfig.xml. The difference is that newSearcher is fired every time a
> commit happens, while firstSearcher is only fired when Solr starts, the
> theory being that there’s no cache autowarming available when Solr fist
> powers up. Usually, people don’t bother with firstSearcher or just make it
> the same as newSearcher. Note that a query doesn’t have to be “real” at
> all. You can just add all the facet fields to a *:* query in a single go.
>     >
>     >    BTW, Trie fields will stay around for a long time even though
> deprecated. Or at least until we find something to replace them with that
> doesn’t have this penalty, so I’d feel pretty safe using those and they’ll
> be more efficient than strings.
>     >
>     >    Best,
>     >    Erick
>     >
>
>

Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
I've been trying to build a query that I can use in newSearcher based off the information in your previous e-mail. I thought you meant to build a *:* query as per Query 1 in my previous e-mail but I'm still seeing the first-hit execution.
Now I'm wondering if you meant to create a *:* query with each of the fields as part of the fl query parameters or a *:* query with each of the fields and values as part of the fq query parameters.

At the moment I've been running these manually as I expected that I would see the first-execution penalty disappear by the time I got to query 4, as I thought this would replicate the actions of the newSeacher.
Unfortunately we can't use the autowarm count that is available as part of the filterCache/filterCache due to the custom deployment mechanism we use to update our index.

Kind Regards,

James Bodkin

On 16/06/2020, 15:30, "Erick Erickson" <er...@gmail.com> wrote:

    Did you try the autowarming like I mentioned in my previous e-mail?

    > On Jun 16, 2020, at 10:18 AM, James Bodkin <ja...@loveholidays.com> wrote:
    > 
    > We've changed the schema to enable docValues for these fields and this led to an improvement in the response time. We found a further improvement by also switching off indexed as these fields are used for faceting and filtering only.
    > Since those changes, we've found that the first-execution for queries is really noticeable. I thought this would be the filterCache based on what I saw in NewRelic however it is probably trying to read the docValues from disk. How can we use the autowarming to improve this?
    > 
    > For example, I've run the following queries in sequence and each query has a first-execution penalty.
    > 
    > Query 1:
    > 
    > q=*:*
    > facet=true
    > facet.field=D_DepartureAirport
    > facet.field=D_Destination
    > facet.limit=-1
    > rows=0
    > 
    > Query 2:
    > 
    > q=*:*
    > fq=D_DepartureAirport:(2660) 
    > facet=true
    > facet.field=D_Destination
    > facet.limit=-1
    > rows=0
    > 
    > Query 3:
    > 
    > q=*:*
    > fq=D_DepartureAirport:(2661)
    > facet=true
    > facet.field=D_Destination
    > facet.limit=-1
    > rows=0
    > 
    > Query 4:
    > 
    > q=*:*
    > fq=D_DepartureAirport:(2660+OR+2661)
    > facet=true
    > facet.field=D_Destination
    > facet.limit=-1
    > rows=0
    > 
    > We've kept the field type as a string, as the value is mapped by application that accesses Solr. In the examples above, the values are mapped to airports and destinations.
    > Is it possible to prewarm the above queries without having to define all the potential filters manually in the auto warming?
    > 
    > At the moment, we update and optimise our index in a different environment and then copy the index to our production instances by using a rolling deployment in Kubernetes.
    > 
    > Kind Regards,
    > 
    > James Bodkin
    > 
    > On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com> wrote:
    > 
    >    I question whether fiterCache has anything to do with it, I suspect what’s really happening is that first time you’re reading the relevant bits from disk into memory. And to double check you should have docVaues enabled for all these fields. The “uninverting” process  can be very expensive, and docValues bypasses that.
    > 
    >    As of Solr 7.6, you can define “uninvertible=true” to your field(Type) to “fail fast” if Solr needs to uninvert the field.
    > 
    >    But that’s an aside. In either case, my claim is that first-time execution does “something”, either reads the serialized docValues from disk or uninverts the file on Solr’s heap.
    > 
    >    You can have this autowarmed by any combination of
    >    1> specifying an autowarm count on your queryResultCache. That’s hit or miss, as it replays the most recent N queries which may or may not contain the sorts. That said, specifying 10-20 for autowarm count is usually a good idea, assuming you’re not committing more than, say, every 30 seconds. I’d add the same to filterCache too.
    > 
    >    2> specifying a newSearcher or firstSearcher query in solrconfig.xml. The difference is that newSearcher is fired every time a commit happens, while firstSearcher is only fired when Solr starts, the theory being that there’s no cache autowarming available when Solr fist powers up. Usually, people don’t bother with firstSearcher or just make it the same as newSearcher. Note that a query doesn’t have to be “real” at all. You can just add all the facet fields to a *:* query in a single go.
    > 
    >    BTW, Trie fields will stay around for a long time even though deprecated. Or at least until we find something to replace them with that doesn’t have this penalty, so I’d feel pretty safe using those and they’ll be more efficient than strings.
    > 
    >    Best,
    >    Erick
    > 


Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
Did you try the autowarming like I mentioned in my previous e-mail?

> On Jun 16, 2020, at 10:18 AM, James Bodkin <ja...@loveholidays.com> wrote:
> 
> We've changed the schema to enable docValues for these fields and this led to an improvement in the response time. We found a further improvement by also switching off indexed as these fields are used for faceting and filtering only.
> Since those changes, we've found that the first-execution for queries is really noticeable. I thought this would be the filterCache based on what I saw in NewRelic however it is probably trying to read the docValues from disk. How can we use the autowarming to improve this?
> 
> For example, I've run the following queries in sequence and each query has a first-execution penalty.
> 
> Query 1:
> 
> q=*:*
> facet=true
> facet.field=D_DepartureAirport
> facet.field=D_Destination
> facet.limit=-1
> rows=0
> 
> Query 2:
> 
> q=*:*
> fq=D_DepartureAirport:(2660) 
> facet=true
> facet.field=D_Destination
> facet.limit=-1
> rows=0
> 
> Query 3:
> 
> q=*:*
> fq=D_DepartureAirport:(2661)
> facet=true
> facet.field=D_Destination
> facet.limit=-1
> rows=0
> 
> Query 4:
> 
> q=*:*
> fq=D_DepartureAirport:(2660+OR+2661)
> facet=true
> facet.field=D_Destination
> facet.limit=-1
> rows=0
> 
> We've kept the field type as a string, as the value is mapped by application that accesses Solr. In the examples above, the values are mapped to airports and destinations.
> Is it possible to prewarm the above queries without having to define all the potential filters manually in the auto warming?
> 
> At the moment, we update and optimise our index in a different environment and then copy the index to our production instances by using a rolling deployment in Kubernetes.
> 
> Kind Regards,
> 
> James Bodkin
> 
> On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com> wrote:
> 
>    I question whether fiterCache has anything to do with it, I suspect what’s really happening is that first time you’re reading the relevant bits from disk into memory. And to double check you should have docVaues enabled for all these fields. The “uninverting” process  can be very expensive, and docValues bypasses that.
> 
>    As of Solr 7.6, you can define “uninvertible=true” to your field(Type) to “fail fast” if Solr needs to uninvert the field.
> 
>    But that’s an aside. In either case, my claim is that first-time execution does “something”, either reads the serialized docValues from disk or uninverts the file on Solr’s heap.
> 
>    You can have this autowarmed by any combination of
>    1> specifying an autowarm count on your queryResultCache. That’s hit or miss, as it replays the most recent N queries which may or may not contain the sorts. That said, specifying 10-20 for autowarm count is usually a good idea, assuming you’re not committing more than, say, every 30 seconds. I’d add the same to filterCache too.
> 
>    2> specifying a newSearcher or firstSearcher query in solrconfig.xml. The difference is that newSearcher is fired every time a commit happens, while firstSearcher is only fired when Solr starts, the theory being that there’s no cache autowarming available when Solr fist powers up. Usually, people don’t bother with firstSearcher or just make it the same as newSearcher. Note that a query doesn’t have to be “real” at all. You can just add all the facet fields to a *:* query in a single go.
> 
>    BTW, Trie fields will stay around for a long time even though deprecated. Or at least until we find something to replace them with that doesn’t have this penalty, so I’d feel pretty safe using those and they’ll be more efficient than strings.
> 
>    Best,
>    Erick
> 


Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
We've changed the schema to enable docValues for these fields and this led to an improvement in the response time. We found a further improvement by also switching off indexed as these fields are used for faceting and filtering only.
Since those changes, we've found that the first-execution for queries is really noticeable. I thought this would be the filterCache based on what I saw in NewRelic however it is probably trying to read the docValues from disk. How can we use the autowarming to improve this?

For example, I've run the following queries in sequence and each query has a first-execution penalty.

Query 1:

q=*:*
facet=true
facet.field=D_DepartureAirport
facet.field=D_Destination
facet.limit=-1
rows=0

Query 2:

q=*:*
fq=D_DepartureAirport:(2660) 
facet=true
facet.field=D_Destination
facet.limit=-1
rows=0

Query 3:

q=*:*
fq=D_DepartureAirport:(2661)
facet=true
facet.field=D_Destination
facet.limit=-1
rows=0

Query 4:

q=*:*
fq=D_DepartureAirport:(2660+OR+2661)
facet=true
facet.field=D_Destination
facet.limit=-1
rows=0

We've kept the field type as a string, as the value is mapped by application that accesses Solr. In the examples above, the values are mapped to airports and destinations.
Is it possible to prewarm the above queries without having to define all the potential filters manually in the auto warming?

At the moment, we update and optimise our index in a different environment and then copy the index to our production instances by using a rolling deployment in Kubernetes.

Kind Regards,

James Bodkin

On 12/06/2020, 18:58, "Erick Erickson" <er...@gmail.com> wrote:

    I question whether fiterCache has anything to do with it, I suspect what’s really happening is that first time you’re reading the relevant bits from disk into memory. And to double check you should have docVaues enabled for all these fields. The “uninverting” process  can be very expensive, and docValues bypasses that.

    As of Solr 7.6, you can define “uninvertible=true” to your field(Type) to “fail fast” if Solr needs to uninvert the field.

    But that’s an aside. In either case, my claim is that first-time execution does “something”, either reads the serialized docValues from disk or uninverts the file on Solr’s heap.

    You can have this autowarmed by any combination of
    1> specifying an autowarm count on your queryResultCache. That’s hit or miss, as it replays the most recent N queries which may or may not contain the sorts. That said, specifying 10-20 for autowarm count is usually a good idea, assuming you’re not committing more than, say, every 30 seconds. I’d add the same to filterCache too.

    2> specifying a newSearcher or firstSearcher query in solrconfig.xml. The difference is that newSearcher is fired every time a commit happens, while firstSearcher is only fired when Solr starts, the theory being that there’s no cache autowarming available when Solr fist powers up. Usually, people don’t bother with firstSearcher or just make it the same as newSearcher. Note that a query doesn’t have to be “real” at all. You can just add all the facet fields to a *:* query in a single go.

    BTW, Trie fields will stay around for a long time even though deprecated. Or at least until we find something to replace them with that doesn’t have this penalty, so I’d feel pretty safe using those and they’ll be more efficient than strings.

    Best,
    Erick


Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
I question whether fiterCache has anything to do with it, I suspect what’s really happening is that first time you’re reading the relevant bits from disk into memory. And to double check you should have docVaues enabled for all these fields. The “uninverting” process  can be very expensive, and docValues bypasses that.

As of Solr 7.6, you can define “uninvertible=true” to your field(Type) to “fail fast” if Solr needs to uninvert the field.

But that’s an aside. In either case, my claim is that first-time execution does “something”, either reads the serialized docValues from disk or uninverts the file on Solr’s heap.

You can have this autowarmed by any combination of
1> specifying an autowarm count on your queryResultCache. That’s hit or miss, as it replays the most recent N queries which may or may not contain the sorts. That said, specifying 10-20 for autowarm count is usually a good idea, assuming you’re not committing more than, say, every 30 seconds. I’d add the same to filterCache too.

2> specifying a newSearcher or firstSearcher query in solrconfig.xml. The difference is that newSearcher is fired every time a commit happens, while firstSearcher is only fired when Solr starts, the theory being that there’s no cache autowarming available when Solr fist powers up. Usually, people don’t bother with firstSearcher or just make it the same as newSearcher. Note that a query doesn’t have to be “real” at all. You can just add all the facet fields to a *:* query in a single go.

BTW, Trie fields will stay around for a long time even though deprecated. Or at least until we find something to replace them with that doesn’t have this penalty, so I’d feel pretty safe using those and they’ll be more efficient than strings.

Best,
Erick

> On Jun 12, 2020, at 12:39 PM, James Bodkin <ja...@loveholidays.com> wrote:
> 
> We've run the performance test after changing the fields to be of the type string. We're seeing improved performance, especially after the first time the query has run. The first run is taking around 1-2 seconds rather than 6-8 seconds and when the filter cache is present, the response time is around 400ms.
> Do you have any more suggestions that we could try in order to optimise the performance?
> 
> On 11/06/2020, 14:49, "Erick Erickson" <er...@gmail.com> wrote:
> 
>    There’s a lot of confusion about using points-based fields for faceting, see: https://issues.apache.org/jira/browse/SOLR-13227 for instance.
> 
>    Two options you might try:
>    1> copyField to a string field and facet on that (won’t work, of course, for any kind of interval/range facet)
>    2> use the deprecated Trie field instead. You could use the copyField to a Trie field for this too.
> 
>    Best,
>    Erick
> 


Re: Facet Performance

Posted by James Bodkin <ja...@loveholidays.com>.
We've run the performance test after changing the fields to be of the type string. We're seeing improved performance, especially after the first time the query has run. The first run is taking around 1-2 seconds rather than 6-8 seconds and when the filter cache is present, the response time is around 400ms.
Do you have any more suggestions that we could try in order to optimise the performance?

On 11/06/2020, 14:49, "Erick Erickson" <er...@gmail.com> wrote:

    There’s a lot of confusion about using points-based fields for faceting, see: https://issues.apache.org/jira/browse/SOLR-13227 for instance.

    Two options you might try:
    1> copyField to a string field and facet on that (won’t work, of course, for any kind of interval/range facet)
    2> use the deprecated Trie field instead. You could use the copyField to a Trie field for this too.

    Best,
    Erick


Re: Facet Performance

Posted by Erick Erickson <er...@gmail.com>.
There’s a lot of confusion about using points-based fields for faceting, see: https://issues.apache.org/jira/browse/SOLR-13227 for instance.

Two options you might try:
1> copyField to a string field and facet on that (won’t work, of course, for any kind of interval/range facet)
2> use the deprecated Trie field instead. You could use the copyField to a Trie field for this too.

Best,
Erick

> On Jun 11, 2020, at 9:39 AM, James Bodkin <ja...@loveholidays.com> wrote:
> 
> We’ve been running a load test against our index and have noticed that the facet queries are significantly slower than we would like.
> Currently these types of queries are taking several seconds to execute and are wondering if it would be possible to speed these up.
> Repeating the same query over and over does not improve the response time so does not appear to utilise any caching.
> Ideally we would like to be targeting a response time around tens or hundreds of milliseconds if possible.
> 
> An example query that is taking around 2-3 seconds to execute is:
> 
> q=*.*
> facet=true
> facet.field=D_UserRatingGte
> facet.mincount=1
> facet.limit=-1
> rows=0
> 
> "response":{"numFound":18979503,"start":0,"maxScore":1.0,"docs":[]}
> "facet_counts":{
>    "facet_queries":{},
>    "facet_fields":{
>      "D_UserRatingGte":[
>        "1575",16614238,
>        "1576",16614238,
>        "1577",16614238,
>        "1578",16065938,
>        "1579",12079545,
>        "1580",458799]},
>    "facet_ranges":{},
>    "facet_intervals":{},
>    "facet_heatmaps":{}}}
> 
> I have also tried the equivalent query using the JSON Facet API with the same outcome of slow response time.
> Additionally I have tried changing the facet method (on both facet apis) with the same outcome of slow response time.
> 
> The underlying field for the above query is configured as a solr.IntPointField with docValues, indexed and multiValued set to true.
> The index has just under 19 million documents and the physical size on disk is 10.95GB. The index is read-only and consists of 4 segments with 0 deletions.
> We’re running standalone Solr 8.3.1 with a 8GB Heap and the underlying Google Cloud Virtual Machine in our load test environment has 6 vCPUs, 32G RAM and 100GB SSD.
> 
> Would anyone be able to point me in a direction to either improve the performance or understand the current performance is expected?
> 
> Kind Regards,
> 
> James Bodkin