Солр/Луценский бомбардир

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

Проблема в том, что они хотят, чтобы результаты попадали в ведра:

  • Ковш 1: точное соответствие по категории (оценка = 4)
  • Ведро 2: точное совпадение имени (оценка = 3)
  • Ведро 3: частичное совпадение по категории (оценка = 2)
  • Ведро 4: частичное совпадение имени (оценка = 1)

Первое, что мы сделали, это разработать собственный класс подобия, который вернет правильный результат в зависимости от поля и точного или частичного соответствия.

Единственная проблема теперь в том, что когда документ соответствует как категории, так и имени, баллы добавляются вместе.

Пример: поиск "ресторана" возвращает документы в ресторан категории, в котором также есть слово ресторан на свое имя и, таким образом, получить оценку 5 (4 + 1), но они должны получить только 4.

Я предполагаю, что для этого нам нужно разработать собственный класс Scorer, но мы не имеем понятия о том, как включить его в Solr. Другим вариантом является создание пользовательской реализации SortField, аналогичной RandomSortField, уже присутствующей в Solr.

Возможно, есть еще более простое решение, о котором мы не знаем.

Приветствуем все предложения!

Ответ 1

Счетчик - это части запросов lucene с помощью метода запросов "вес".

Вкратце, структура вызывает Query.weight(..). scorer (..). Посмотрите

http://lucene.apache.org/java/2_4_0/api/org/apache/lucene/search/Query.html

http://lucene.apache.org/java/2_4_0/api/org/apache/lucene/search/Weight.html

http://lucene.apache.org/jva/2_4_0/api/org/apache/lucene/search/Scorer.html

Чтобы использовать свой собственный класс Query в Solr, вам нужно реализовать свой собственный solr QueryParserPlugin, который использует ваш собственный QParser, который генерирует ваш ранее реализованный запрос lucene. Затем вы можете использовать его в Solr, указанном здесь:

http://wiki.apache.org/solr/SolrPlugins#QParserPlugin

Эта часть реализации должна оставаться простой, поскольку это всего лишь некоторый код склеивания.

Наслаждайтесь взломом Solr!

Ответ 2

Вы можете переопределить использование логического контроллера. Solr использует класс DefaultSimilarity для подсчета очков.

Сделать класс, расширяющий DefaultSimilarity и переопределить функции tf(), idf() и т.д. в соответствии с вашими потребностями:
public class CustomSimilarity extends DefaultSimilarity {

  public CustomSimilarity() {
    super();
  }

  public float tf(int freq) {
    //your code  
    return (float) 1.0;
  }

  public float idf(int docFreq, int numDocs) {
    //your code
    return (float) 1.0;
  }

}

После создания класса компилируйте и создайте банку. Поместите банку в папку lib соответствующего индекса или ядра. Измените schema.xml соответствующего индекса: <similarity class="<your package name>.CustomSimilarity"/>

Вы можете проверить различные факторы, влияющие на оценку здесь

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

Ответ 4

Спасибо за хорошие ответы выше. Просто добавив к ним, установив это в Solr 4.2.1, что позволяет подойти к полю. (До Solr 4 вы могли только изменить сходство для всех полей по всему миру.)

Скажем, мы хотим, чтобы Solr не использовал инверсную частоту документа (idf) для определенного поля - для этого мы должны написать собственное сходство, подобное упомянутому выше:

package com.mycompany.similarity;

import org.apache.lucene.search.similarities.DefaultSimilarity;

public class NoIDFSimilarity extends DefaultSimilarity
{
    @Override
    public float idf(long docFreq, long numDocs)
    {
        return 1.0f;
    }

    @Override
    public String toString()
    {
        return "NoIDFSimilarity";
    }
}

а затем в нашем schema.xml определите новый тип fieldType следующим образом:

<fieldType name="int_no_idf" 
           class="solr.TrieIntField" 
           precisionStep="0" 
           positionIncrementGap="0" 
           omitNorms="true">
    <similarity class="com.mycompany.similarity.NoIDFSimilarity"/>
</fieldType>

и использовать его в таком поле:

<field name="tag_id_no_idf" 
       type="int_no_idf" 
       indexed="true" 
       stored="false" 
       multiValued="true" />

Если бы мы сделали только это, то вы получите следующее исключение:

SEVERE: Unable to create core: SimilarList
org.apache.solr.common.SolrException: FieldType 'int_no_idf' is configured with a similarity, but the global similarity does not support it: class org.apache.solr.search.similarities.DefaultSimilarityFactory
    at org.apache.solr.schema.IndexSchema.readSchema(IndexSchema.java:466)
    at org.apache.solr.schema.IndexSchema.<init>(IndexSchema.java:122)
    at org.apache.solr.core.CoreContainer.createFromLocal(CoreContainer.java:1018)
    at org.apache.solr.core.CoreContainer.create(CoreContainer.java:1051)
    at org.apache.solr.core.CoreContainer$3.call(CoreContainer.java:634)
    at org.apache.solr.core.CoreContainer$3.call(CoreContainer.java:629)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Apr 25, 2013 5:02:08 PM org.apache.solr.common.SolrException log
SEVERE: null:org.apache.solr.common.SolrException: Unable to create core: SimilarList
    at org.apache.solr.core.CoreContainer.recordAndThrow(CoreContainer.java:1672)
    at org.apache.solr.core.CoreContainer.create(CoreContainer.java:1057)
    at org.apache.solr.core.CoreContainer$3.call(CoreContainer.java:634)
    at org.apache.solr.core.CoreContainer$3.call(CoreContainer.java:629)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.apache.solr.common.SolrException: FieldType 'int_no_idf' is configured with a similarity, but the global similarity does not support it: class org.apache.solr.search.similarities.DefaultSimilarityFactory
    at org.apache.solr.schema.IndexSchema.readSchema(IndexSchema.java:466)
    at org.apache.solr.schema.IndexSchema.<init>(IndexSchema.java:122)
    at org.apache.solr.core.CoreContainer.createFromLocal(CoreContainer.java:1018)
    at org.apache.solr.core.CoreContainer.create(CoreContainer.java:1051)
    ... 10 more

Поиск в google приведет вас к this, поэтому просто добавьте эту строку в свой schema.xml, который будет применяться к остальным полям

<similarity class="solr.SchemaSimilarityFactory"/>

(Из этой ссылки: но имейте в виду, что координаты и queryNorm (= 1.0f) теперь не реализованы, поэтому вы получите разные баллы для TF-IDF!)