Статьи

Расширенный фильтр кэширования в Solr

Advanced Filter Caching — это относительно новая функция в Solr, доступная в версии 3.4 и выше. Это позволяет точно контролировать, как Solr обрабатывает запросы на фильтрацию, чтобы максимизировать производительность, включая возможность указать, кэшируется ли фильтр, оцениваются ли фильтры порядка, и постфильтрации.

Фильтр запросов в Solr

Добавление фильтра, выраженного как запрос к запросу Solr, совсем несложно … просто добавьте дополнительный параметр fq для каждого запроса фильтра .

http://localhost:8983/solr/select?
   q=cars
   &fq=color:red
   &fq=model:Corvette
   &fq=year:[2005 TO *]

По умолчанию Solr разрешает все фильтры * перед * основным запросом. Каждый запрос фильтра просматривается отдельно в filterCache Solr (который сам по себе довольно продвинутый, поддерживает одновременный поиск , различные политики удаления, такие как LRU или LFU и автоматическое нагревание ). Кэширование каждого запроса фильтра в отдельности ускоряет пропускную способность запросов Solr, значительно улучшая частоту обращений в кэш, поскольку многие типы фильтров, как правило, повторно используются в разных запросах.

Кэшировать или не кэшировать

Новый расширенный API управления фильтрами добавляет возможность * не * кэшировать фильтр. Некоторые фильтры могут практически не повторять использование в разных запросах, и отсутствие попыток их кэшировать может привести к уменьшению и повышению эффективности filterCache с более высокой частотой обращений.

Чтобы указать Solr не кэшировать фильтр, мы используем тот же мощный DSL локальных параметров, который добавляет метаданные к параметрам запроса и используется для указания различных типов синтаксиса запросов и анализаторов запросов. Для обычного запроса, который не имеет метаданных localParam, просто добавьте локальный параметр cache = false . Например:

&fq={!cache=false}year:[2005 TO *]

Чтобы добавить cache = false к фильтру, который уже имел localParams, просто добавьте его прямо к остальным параметрам. Например, если мы хотим использовать собственные пространственные возможности Solr, чтобы ограничить наши совпадения местоположениями в пределах 50 км от Стэнфорда, наш запрос фильтра будет выглядеть следующим образом:

&fq={!geofilt sfield=location pt=37.42,-122.17 d=50} 

It’s easy to modify this filter to tell Solr not to cache it by adding cache=false in with the rest of the local parameters:

&fq={!geofilt sfield=location pt=37.42,-122.17 d=50 cache=false} 

Leapfrog anyone?

When a filter isn’t generated up front and cached, it’s executed in parallel with the main query. First, the filter is asked about the first document id that it matches. The query is then asked about the first document that is equal to or greater than that document. The filter is then asked about the first document that is equal to or greater than that. The filter and the query play this game of leapfrog until they land on the same document and it’s declared a match, after which the document is collected and scored.

How much is that filter?

Advanced filtering adds even more fine grained control by introducing the notion of cost. If there are multiple non-cached filters in a response, filters with a lower cost will be checked before those with a higher cost.

&fq={!cache=false cost=10}year:[2005 TO *]
&fq={!geofilt cache=false cost=20}
&pt=37.42,-122.17
&sfield=location
&d=50

In the example above, the filter based on year has a lower cost and will thus always be checked before the spatial filter.

As an aside, notice how spatial queries will use global spatial request parameters if they are not specified locally. This can make it even easier to construct requests containing spatial functions.

Expensive Filters

Some filters are slow enough that you don’t even want to run them in parallel with the query and other filters, even if they are consulted last, since asking them “what is the next doc you match on or after this given doc” is so expensive. For these types of filters, you really want to only ask them “do you match this doc” only after the query and all other filters have been consulted. Solr has special support for this called “post filtering“.

Post filtering is triggered by filters that have a cost>=100 and have explicit support for it. If there are multiple post filters in a single request, they will be ordered by cost.

The frange qparser has post filter support and allows powerful queries specifying ranges over arbitrarily complex function queries.

For example, if we wanted to take the log of popularity, divide it by the square root of the distance, and filter out documents with a result less than 5, we could run this as a post filter using frange:

&fq={!frange l=5 cache=false cost=200}div(log(popularity),sqrt(geodist()))

Post filtering support for the spatial filter queries bbox and geofilt has just been added to Solr 4.0 too. To execute our previous un-cached spatial filter as a post filter, simply modify it’s cost to be greater than 100:

&fq={!geofilt cache=false cost=150}
&pt=37.42,-122.17
&sfield=location
&d=50

Custom Filters

If you have expensive custom logic you’d like to add as a post filter (say per-document custom security ACLs), you can implement your own QParserPlugin that returns Query objects that implement Solr’s PostFilter interface. You can set the default cost or hardcode a cost higher than 100 if you want to only support post filtering. Then, you can use your custom parser as you would any other builtin query type via fq={!myqueryparser} and Solr will handle the rest!

Try it out!

In conclusion, hopefully this gives more insight into just one of many factors working under the hood to make Solr so fast.
To try out the latest functionality, you can always get a nightly build of trunk. Feedback is always appreciated!

Source:  http://www.lucidimagination.com/blog/2012/02/10/advanced-filter-caching-in-solr/