Пример иерархического фасетного поиска с Solr

Вопрос

Где я могу найти полный пример, показывающий, как работает иерархический фасетный поиск от индексации документов до получения результатов поиска?

Мои исследования на данный момент

В Stackoverflow есть несколько сообщений, но все они затрагивают только определенные аспекты иерархического фасетного поиска; поэтому я бы не стал считать их дубликатами. Я ищу полный пример, чтобы понять это. Мне не хватает последнего запроса, в котором работают агрегаты.

На веб-странице Solr есть документация, но я не понял приведенный там пример.

Пример (концептуально)

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

Testdata

Ввод

Допустим, у нас есть 3 документа, каждый из которых является человеком.

Alice (document 1)
 - Blond
 - Europe

Jane (document 2)
 - Brown
 - Europe/Norway

Bob (document 3)
 - Brown
 - Europe/Norway
 - Europe/Sweden

Вывод

Ожидаемый результат для этого (в настоящее время неверного) запроса

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true&facet=true&facet.field=tags_ss

должно быть

Hair_color (3)
- blond (1)
- brown (1)
- black (1)

Location (3)
- Europe (4)  // This should be 4 not 3, i.e. the sum of the leaves, because Alice is tagged with "Europe" only, without a country
  - Norway (2)
  - Sweden (1)

потому что все документы найдены.

Пример (программно)

Вот где мне нужна помощь. Как мне реализовать приведенный выше концептуальный пример?

Вот как далеко я зашел.

1. Создайте тестовые данные XML

Это содержимое файла documents.xml в подпапке solr-5.1.0/testdata:

<add>
    <doc>
        <field name="id">Alice</field>
        <field name="tags_ss">hair_color/blond</field>
        <field name="tags_ss">location/Europe</field>
    </doc>
    <doc>
        <field name="id">Jane</field>
        <field name="tags_ss">hair_color/brown</field>
        <field name="tags_ss">location/Europe/Norway</field>
    </doc>
    <doc>
        <field name="id">Bob</field>
        <field name="tags_ss">hair_color/black</field>
        <field name="tags_ss">location/Europe/Norway</field>
        <field name="tags_ss">location/Europe/Sweden</field>
    </doc>
</add>

_ss определяется в schema.xml как

<dynamicField name="*_ss" type="string"  indexed="true"  stored="true" multiValued="true"/>

Обратите внимание, что все теги, например hair_color и location и другие теги, которые будут добавлены в будущем, хранятся в том же поле tags_ss.

2. Индексируйте тестовые данные с помощью Solr

c:\solr-5.1.0>java -classpath dist/solr-core-5.1.0.jar -Dauto=yes -Dc=gettingstarted -Ddata=files -Drecursive=yes -Durl=http://server:8983/solr/my_core/update org.apache.solr.util.SimplePostTool .\testdata

Страница статистики Solr

3. Получить все данные с помощью запроса Solr (без фасетирования)

Запрос

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true

Результат

{
  "responseHeader": {
    "status": 0,
    "QTime": 0,
    "params": {
      "indent": "true",
      "q": "*:*",
      "_": "1430830360536",
      "wt": "json"
    }
  },
  "response": {
    "numFound": 3,
    "start": 0,
    "docs": [
      {
        "id": "Alice",
        "tags_ss": [
          "hair_color/blond",
          "location/europe"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Jane",
        "tags_ss": [
          "hair_color/brown",
          "location/europe/Norway"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Bob",
        "tags_ss": [
          "hair_color/black",
          "location/europe/Norway",
          "location/europe/Sweden"
        ],
        "_version_": 1500334369469890600
      }
    ]
  }
}

4. Получить все данные с помощью запроса Solr (с фасетированием)

Запрос

http://server:8983/solr/my_core/select?q=*%3A*&wt=json&indent=true&facet=true&facet.field=tags_ss

Результат

{
  "responseHeader": {
    "status": 0,
    "QTime": 0,
    "params": {
      "facet": "true",
      "indent": "true",
      "q": "*:*",
      "_": "1430830432389",
      "facet.field": "tags_ss",
      "wt": "json"
    }
  },
  "response": {
    "numFound": 3,
    "start": 0,
    "docs": [
      {
        "id": "Alice",
        "tags_ss": [
          "hair_color/blond",
          "location/europe"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Jane",
        "tags_ss": [
          "hair_color/brown",
          "location/europe/Norway"
        ],
        "_version_": 1500334369469890600
      },
      {
        "id": "Bob",
        "tags_ss": [
          "hair_color/black",
          "location/europe/Norway",
          "location/europe/Sweden"
        ],
        "_version_": 1500334369469890600
      }
    ]
  },
  "facet_counts": {
    "facet_queries": {},
    "facet_fields": {
      "tags_ss": [
        "location/europe/Norway",
        2,
        "hair_color/black",
        1,
        "hair_color/blond",
        1,
        "hair_color/brown",
        1,
        "location/europe",
        1,
        "location/europe/Sweden",
        1
      ]
    },
    "facet_dates": {},
    "facet_ranges": {},
    "facet_intervals": {},
    "facet_heatmaps": {}
  }
}

Обратите внимание на этот раздел внизу результата:

"facet_fields": {
  "tags_ss": [
    "location/europe/Norway",
    2,
    "hair_color/black",
    1,
    "hair_color/blond",
    1,
    "hair_color/brown",
    1,
    "location/europe",
    1,
    "location/europe/Sweden",
    1
  ]
},

Он показывает все теги в виде плоского списка (не иерархического).

5. Получить все данные с помощью запроса Solr (с иерархическим фасетом)

Запрос

Вот моя проблема. Я не знаю, как составить запрос, который возвращает следующий результат (результат уже показан в концептуальном примере выше).

Результат (вымышленный, создан вручную для иллюстрации)

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "facet":"true",
      "indent":"true",
      "q":"*:*",
      "facet.field":"tags_ss",
      "wt":"json",
      "rows":"0"}},
  "response":{"numFound":3,"start":0,"docs":[]
  },
  "facet_counts":{
    "facet_queries":{},
    "facet_fields":{
      "tags_ss":[
        "hair_color,3, // This aggregations is missing
        "hair_color/black",1,
        "hair_color/blond",1,
        "hair_color/brown",1,
        "location/europe",4, // This aggregation should be 4 but is 1
        "location/europe/Norway",2,
        "location/europe/Sweden",1]},
    "facet_dates":{},
    "facet_ranges":{},
    "facet_intervals":{},
    "facet_heatmaps":{}}}

Этот список тегов все еще плоский, но по крайней мере location/europe = 4 можно было бы правильно агрегировать, но в настоящее время это не так. Я продолжаю получать location/europe = 1, потому что он установлен только для Alice, а Bob Norway и Sweden не суммируются, чтобы также засчитывать Europe.

Идеи

  • Мне может понадобиться использовать facet.pivot, но я не знаю как.
  • Мне может понадобиться использовать facet.prefix, но я не знаю как.

Версии

  • Solr 5.1.0
  • Windows 7

person Lernkurve    schedule 05.05.2015    source источник


Ответы (1)


Вы можете заполнить все ваши агрегаты, если вы будете помещать их в индекс поэтапно. Если Боб из Норвегии, вы можете указать до трех значений в поле фасета:

location
location/Europe
location/Europe/Norway

(В качестве альтернативного варианта у вас может быть поле цвета волос отдельно от поля местоположения, и тогда «местоположение» никогда не нужно будет заполнять в самом поле.)

Тогда ваши результаты останутся неизменными, но будут присутствовать ваши агрегированные итоги. На этом этапе вам нужно будет выполнить некоторую программную работу с набором результатов, чтобы создать вложенную структуру данных, построенную путем разделения всех значений на символ-разделитель (в данном случае /). Если у вас есть вложенная структура данных, ее иерархическое отображение должно стать управляемым. Трудно вдаваться в подробности этой части реализации, потому что ваша вложенная структура данных и отображение будут сильно зависеть от вашей среды разработки.

Другой, несколько рискованный вариант избежать добавления повторяющихся записей в поле фасета Solr - добавить только то значение, которое вы используете сейчас (например, location/Europe/Norway), но суммировать итоговые суммы листьев по мере прохождения списка фасетов и построения вложенных данных. структура. Существует риск того, что, если человек действительно связан с несколькими странами Европы, вы можете получить завышенную сумму для более высокого уровня location/Europe. В своих проектах я выбрал заполнение отдельных значений, как указано выше. Хотя они кажутся избыточными, общие итоги оказываются более точными.

(Как обычно в Solr, это только один из многих способов сделать что-то. Эта модель лучше всего работает для систем с управляемым количеством общих выходов, где имеет смысл извлекать все значения фасетов заранее и не нужно сделать дополнительные запросы детализации.)

Возможность поворота

Поворот фасета Solr может возвращать иерархически структурированный результат непосредственно из Solr, но в определенных ситуациях рискует создать ложные связи между значениями.

Итак, допустим, вы загружаете свои документы следующим образом:

<add>
 <doc>
  <field name="id">Alice</field>
  <field name="continent">Europe</field>
 </doc>
 <doc>
  <field name="id">Jane</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
 </doc>
 <doc>
  <field name="id">Bob</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
  <field name="country">Sweden</field>
 </doc>
</add>

Теперь вы выполняете запрос сводки фасетов с facet.pivot.mincount=1&facet.pivot=continent,country. Пока результаты могут быть отличными:

"facet_pivot":{
 "continent,country":[{
  "field":"continent",
  "value":"Europe",
  "count":3,
  "pivot":[{
    "field":"country",
    "value":"Norway",
    "count":2,},
      {
    "field":"country",
    "value":"Sweden",
    "count":1,}]}]}

Все идет нормально. Проблема возникает, когда вы добавляете в данные нового человека:

<add>
 <doc>
  <field name="id">Susan</field>
  <field name="continent">Europe</field>
  <field name="country">Norway</field>
  <field name="continent">South America</field
  <field name="country">Brazil</field>
 </doc>
</add>

Теперь Solr на самом деле не знает, что Норвегия находится в Европе, а Бразилия - в Южной Америке, поэтому вы начнете получать подсчеты аспектов для «Европа> Бразилия» и «Южная Америка> Норвегия».

Проблема решается, если вы добавите префиксы континентов ко всем значениям вашей страны:

<add>
 <doc>
  <field name="id">Susan</field>
  <field name="continent">Europe</field>
  <field name="country">Europe/Norway</field>
  <field name="continent">South America</field
  <field name="country">South America/Brazil</field>
 </doc>
</add>

Таким образом, вы по-прежнему будете получать несоответствующие значения сводной таблицы, но вы можете заблокировать любые значения фасетов на уровне страны, у которых нет префикса, соответствующего их континенту. Чтобы это стало проблемой, многозначное поле в сводной таблице должно иметь значения, связанные со значениями, появляющимися позже в той же сводной таблице. Если вы не ожидаете иметь несколько значений для этих полей в одной записи или если ваши значения не имеют сильной связи (то есть определенного происхождения), аспекты сводной таблицы могут быть идеальным решением. Но в некоторых случаях диссоциация сводного аспекта между значениями во включенных полях может создать недопустимый беспорядок.

person frances    schedule 05.05.2015
comment
Спасибо. Просто для пояснения: означает ли это, что если я заполняю поле Bob tag_ss только location/europe/Norway вместо трех значений location, location/Europe и location/Europe/Norway, как вы предлагаете, Solr не способен разделить его и агрегировать? Это правильно? Я бы надеялся иначе; Я бы надеялся, что Солр сделает всю работу за меня. - person Lernkurve; 05.05.2015
comment
Он может делать это с фасетами поворота, но не без оговорок. Это было слишком много, чтобы объяснять в комментарии, поэтому я отредактировал свой ответ. - person frances; 05.05.2015
comment
Я также заметил, что несколько раз в своем вопросе вы указали, что совокупное количество для Европы должно быть 4. Я действительно не думал об этом в моем первом проходе, но важно отметить, что количество фасетов Solr всегда учитывает совпадение записи, не соответствующие полям. Независимо от того, сколько раз одна запись ссылается на Европу, она никогда не будет учитываться более одного раза при подсчете аспектов. - person frances; 05.05.2015