Статьи

Комплекс Солр Гранит


При использовании граней Solr рано или поздно возникает запрос на сложный фасет, который на первый взгляд кажется невозможным при использовании стандартной фасовки Solr.
Однако с помощью творческого использования фасетов и небольшого количества дополнительной логики в вашем приложении вы можете создать очень продвинутый интерфейс фасетирования. В этом примере я объясню:

  • Как создать несколько фасетов в одном поле, используя ключ для уникального имени и исключив теговые запросы фильтра для разных подсчетов
  • Как использовать результаты множественного подсчета фасетов для визуализации одного элемента интерфейса

Лучший способ объяснить это — использовать тестовую настройку с хорошим набором данных. В следующих примерах я буду использовать ту же настройку теста, что и в (превосходной!) Книге « Solr 1.4 Enterprise Search Server », на основе данных MusicBrainz.
Если вы прочитали книгу и у вас есть тестовая среда, вы уже знаете этот набор данных и можете самостоятельно тестировать запросы, я объясню наиболее важные части индекса для других. Но я предполагаю, что вы хорошо понимаете основы Solr (огранки) для остальной части этого примера, так как я не буду объяснять базовое использование Solr.

Я буду использовать индекс ‘mbtracks’, который содержит всевозможные (музыкальные) треки. Для простоты примера я буду использовать только несколько полей для запросов фильтра и фасетирования, наиболее важным является поле ‘t_r_attributes’. Это многозначное целочисленное поле с таким содержимым (перечисляемым):

фасет-пример0 = дорожка без альбома
1 = Альбом
2 = Одиночный
3 = EP
4 = Компиляция
5 = Саундтрек
6 = Spokenword
7 = Интервью
8 = Аудиокнига
9 = Live
10 = Remix
11 = Другое
100 = Официальный
101 = Продвижение
102 = Бутлег
103 = Псевдо-релиз

Обратите внимание, что 0-11 являются «типами релизов», а 100-103 являются индикаторами официального состояния. Таким образом, фактически два отдельных списка сохраняются в одном многозначном поле. Большинство строк будут иметь по одной из каждой, например, «1» и «100» для дорожки, выпущенной на официальном альбоме.

Теперь представьте следующий сценарий: сайт строится с использованием этого индекса Solr. На веб-сайте есть специальная страница «Псевдо-релизы », которая позволяет пользователям применять дополнительные фильтры для «типа выпуска» и «продолжительности». Смотри мой очень простой набросок выше.
Фасет «тип выпуска» имеет некоторые специальные функции, на эскизе вы можете увидеть их все:

  • Один выбранный фасет ‘Альбом’ с количеством.
  • Один доступный фасет ‘Single’ с количеством.
  • Один аспект «EP», который выделен серым цветом. Это указывает на то, что существуют аудиокниги с атрибутом «псевдо-релиз», но они исключаются другими выбранными параметрами фасета, такими как «продолжительность». Количество представляет количество исключенных элементов.
  • Один аспект «интервью» с «N / A» указывает на то, что вообще нет «интервью» с атрибутом «псевдо-релиз», но он существует как «тип релиза».


Конечно, вы можете поставить под сомнение этот дизайн. Зачем показывать опции, которые в любом случае недоступны? Как мне ожидать, что пользователь поймет различные типы опций? Хорошие вопросы для дизайна реального мира, но это был лучший пример, который я мог восполнить для этого набора данных. Есть много реальных случаев, когда это имеет гораздо больше смысла.

Особенности этого фасета делают невозможным его создание из обычного (одиночного) фасета Solr. Важно отметить, что требования фактически объединяют несколько различных типов огранки в один элемент пользовательского интерфейса. После того, как вы определили различные типы данных фасетов, которые вам нужны, вы можете получить эти данные с использованием нескольких фасетов и пометки / исключения. И после выполнения запроса Solr вы можете визуализировать элемент на основе объединенных данных.

Давайте сначала начнем с базового запроса. Сначала читаемая и прокомментированная версия, а затем копируемая версия для удобства тестирования.

http://localhost:8983/solr/mbtracks/select/
> path to solr index...
?q=*%3A*&version=2.2&start=0&rows=10&indent=on
> query any documents and some standard Solr settings
&fq={!tag=releasefilter}t_r_attributes:103
> filterquery on 'pseudo releases', note the tag
&facet=on
&facet.mincount=1
> enable faceting and set mincount to 1
&facet.field={!key=attributes}t_r_attributes
> facet on attributes, note the 'key' that allows for multiple facets on the same field
&facet.field={!key=na_attributes ex=releasefilter}t_r_attributes
> facet on the same field, but this time excluding the releasefilter!
&facet.query={!key=duration_short}t_duration:[*  TO 120]
&facet.query={!key=duration_long}t_duration:[120 TO *]
> facet queries for duration, using keys for a easy to use resultset
http://localhost:8983/solr/mbtracks/select/?q=*%3A*&fq={!tag=releasefilter}t_r_attributes:103&version=2.2&start=0&rows=10&indent=on&facet=on&facet.mincount=1&facet.field={!key=attributes}t_r_attributes&facet.field={!key=na_attributes ex=releasefilter}t_r_attributes&facet.query={!key=duration_short}t_duration:[* TO 120]&facet.query={!key=duration_long}t_duration:[120 TO *]

В базовом запросе есть два аспекта для типов выпуска. Один для подсчета доступных типов выпуска, а другой для N / A. В этом случае второй фасет не требуется, тот же результат может быть достигнут с помощью одного фасета с facet.mincount, установленным в 0. Но его базовый запрос легче построить для следующего примера, сложного запроса, где пользователь выбрал типы релизов 1 и 2 (альбом и одиночный) и длительность «короткая»:

http://localhost:8983/solr/mbtracks/select/
?q=*%3A*&version=2.2&start=0&rows=10&indent=on
&fq={!tag=releasefilter}t_r_attributes:103
&fq={!tag=durationfilter}t_duration:[* TO 120]
&fq={!tag=userchoice}t_r_attributes:1 OR 2
&facet=on&facet.mincount=1
&facet.field={!key=attributes ex=userchoice}t_r_attributes
> the facet for 'active' attributes takes all filterqueries into account, except chosen categories (so the available ones also get a count)
&facet.field={!key=ruledout_attributes ex=durationfilter,userchoice}t_r_attributes
> the facets counts all attributes that would have been available, had the user not chosen a duration
&facet.field={!key=na_attributes ex=releasefilter,durationfilter,userchoice}t_r_attributes
> facet on all attributes (excludes all filters)
&facet.query={!key=duration_short ex=durationfilter}t_duration:[* TO 120]
&facet.query={!key=duration_long ex=durationfilter}t_duration:[120 TO *]
http://localhost:8983/solr/mbtracks/select/?q=*%3A*&fq={!tag=releasefilter}t_r_attributes:103&fq={!tag=durationfilter}t_duration:[*  TO 120]&fq={!tag=userchoice}t_r_attributes:1 OR  2&version=2.2&start=0&rows=10&indent=on&facet=on&facet.mincount=1&facet.field={!key=attributes}t_r_attributes&facet.field={!key=ruledout_attributes   ex=durationfilter,userchoice}t_r_attributes&facet.field={!key=na_attributes   ex=releasefilter,durationfilter,userchoice}t_r_attributes&facet.query={!key=duration_short  ex=durationfilter}t_duration:[* TO  120]&facet.query={!key=duration_long  ex=durationfilter}t_duration:[120 TO *]

(Сокращенный) XML-результат этого запроса:

<response>
<result name="response" numFound="2186" start="0">
<doc>
<str name="id">Track:1820660</str>
<str name="t_a_id">133473</str>
<str name="t_a_name">Skoop On Somebody</str>
<int name="t_duration">23</int>
<str name="t_name">Introduction</str>
<int name="t_num">1</int>
<arr name="t_r_attributes">
<int>0</int>
<int>1</int>
<int>103</int>
</arr>
<str name="t_r_id">178049</str>
<str name="t_r_name">Key of Love</str>
<int name="t_r_tracks">15</int>
<int name="t_trm_lookups">0</int>
<str name="type">Track</str>
</doc>
</result>
<lst name="facet_counts">
<lst name="facet_queries">
<int name="duration_short">2186</int>
<int name="duration_long">11519</int>
</lst>
<lst name="facet_fields">
<lst name="attributes">
<int name="1">2186</int>
<int name="103">2186</int>
<int name="0">2028</int>
<int name="5">142</int>
<int name="2">4</int>
</lst>
<lst name="ruledout_attributes">
<int name="103">30810</int>
<int name="0">30445</int>
<int name="1">13690</int>
<int name="5">7895</int>
<int name="4">4353</int>
<int name="2">2670</int>
<int name="9">1007</int>
<int name="3">701</int>
<int name="10">399</int>
<int name="6">113</int>
<int name="11">107</int>
<int name="8">12</int>
</lst>
<lst name="na_attributes">
<int name="0">6976389</int>
<int name="100">6009955</int>
<int name="1">3277697</int>
<int name="4">1987317</int>
<int name="9">407872</int>
<int name="102">263344</int>
<int name="5">242589</int>
<int name="2">211736</int>
<int name="3">166152</int>
<int name="101">143203</int>
<int name="10">51606</int>
<int name="11">48602</int>
<int name="8">48167</int>
<int name="6">39555</int>
<int name="103">30810</int>
<int name="7">2406</int>
</lst>
</lst>
<lst name="facet_dates"/>
</lst>
</response>

Результирующий набор содержит все необходимое для визуализации элемента фильтра типа выпуска, и на самом деле это довольно просто:

  1. Визуализируйте элементы из фасета «атрибуты» как доступные элементы, отметив выбранные элементы, а остальные не отметив. Показать подсчет Solr.
  2. Визуализируйте элементы ‘ruledout_attributes’ серым цветом. Не обращайте внимания на подсчет Solr и отображайте ноль, так как фактический отсчет не имеет значения, только тот факт, что будет подсчет, если исключить фильтры.
  3. Визуализируйте «na_attributes» как N / A. Снова подсчет Солра не имеет значения (опять же, важно только то, что есть подсчет )


Важно:
для каждого шага исключите все строки, которые уже были обработаны на предыдущем шаге (по имени).

Для этого набора данных все строки с именем> 100 следует игнорировать, так как они представляют «официальное состояние» вместо «тип выпуска». Также атрибуты с нулевым значением игнорируются, так как каждый отдельный документ имеет это значение атрибута.

После рендеринга вышеуказанных данных вы получите этот элемент интерфейса: