Статьи

Как написать собственный Solr FunctionQuery

Solr FunctionQueries позволяет изменять ранжирование поискового запроса в Solr, применяя функции к результатам.

Список готовых FunctionQueries доступен здесь: http://wiki.apache.org/solr/FunctionQuery

Чтобы написать собственный Solr FunctionQuery, вам нужно сделать 2 вещи:

1. Подкласс org.apache.solr.search.ValueSourceParser . Вот заглушка ValueSourceParser.

public class MyValueSourceParser extends ValueSourceParser {
  public void init(NamedList namedList) {
  }

  public ValueSource parse(FunctionQParser fqp) throws ParseException {
    return new MyValueSource();
  }
}

2. В файле solrconfig.xml зарегистрируйте новый ValueSourceParser непосредственно под тегом <config>.

<valueSourceParser name="myfunc" class="com.mycompany.MyValueSourceParser" />

3. Подкласс org.apache.solr.search.ValueSource и создайте его экземпляр в методе ValueSourceParser.parse ().

Давайте посмотрим на 2 реализации ValueSource, чтобы увидеть, что они делают, начиная с самого простого:

org.apache.solr.search.function.ConstValueSource

Пример SolrQuerySyntax: _val_: 1.5

Он просто возвращает значение с плавающей точкой.

public class ConstValueSource extends ValueSource {
  final float constant;

  public ConstValueSource(float constant) {
    this.constant = constant;
  }

  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    return new DocValues() {
      public float floatVal(int doc) {
        return constant;
      }
      public int intVal(int doc) {
        return (int)floatVal(doc);
      }
      public long longVal(int doc) {
        return (long)floatVal(doc);
      }
      public double doubleVal(int doc) {
        return (double)floatVal(doc);
      }
      public String strVal(int doc) {
        return Float.toString(floatVal(doc));
      }
      public String toString(int doc) {
        return description();
      }
    };
  }
// commented out some boilerplate stuff
}

Как видите, важным методом является DocValues ​​getValues ​​(контекст карты, читатель IndexReader) . Суть метода заключается в возвращении объекта DocValues, который возвращает значение с данным идентификатором документа.

org.apache.solr.search.function.OrdFieldSource

ord (myfield) возвращает порядковый номер значения индексированного поля в индексированном списке терминов для этого поля в порядке индекса lucene (лексикографически упорядоченный по значению юникода), начиная с 1. Другими словами, для данного поля все значения упорядочены лексически; эта функция затем возвращает смещение определенного значения в этом порядке.

Пример SolrQuerySyntax: _val _: «ord (myIndexedField)»

public class OrdFieldSource extends ValueSource {
  protected String field;

  public OrdFieldSource(String field) {
    this.field = field;
  }
  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    return new StringIndexDocValues(this, reader, field) {
      protected String toTerm(String readableValue) {
        return readableValue;
      }
     
      public float floatVal(int doc) {
        return (float)order[doc];
      }

      public int intVal(int doc) {
        return order[doc];
      }

      public long longVal(int doc) {
        return (long)order[doc];
      }

      public double doubleVal(int doc) {
        return (double)order[doc];
      }

      public String strVal(int doc) {
        // the string value of the ordinal, not the string itself
        return Integer.toString(order[doc]);
      }

      public String toString(int doc) {
        return description() + '=' + intVal(doc);
      }
    };
  }
}

OrdFieldSource практически идентичен ConstValueSource, основными отличиями которого являются возврат порядка, а не константного значения, и использование StringIndexDocValues ​​для получения порядка значений.

Наш собственный ValueSource

Теперь у нас есть довольно хорошее представление о том, что должен делать подкласс ValueSource:

вернуть некоторое значение для данного идентификатора документа .

Это может быть основано на значении поля в индексе (например, OrdFieldSource) или вообще не связано с индексом (например, ConstValueSource).

Вот тот, который выполняет противоположность MaxFloatFunction / max () — MinFloatFunction / min ():

public class MinFloatFunction extends ValueSource {
  protected final ValueSource source;
  protected final float fval;

  public MinFloatFunction(ValueSource source, float fval) {
    this.source = source;
    this.fval = fval;
  }
 
  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    final DocValues vals =  source.getValues(context, reader);
    return new DocValues() {
      public float floatVal(int doc) {
    float v = vals.floatVal(doc);
        return v > fval ? fval : v;
      }
      public int intVal(int doc) {
        return (int)floatVal(doc);
      }
      public long longVal(int doc) {
        return (long)floatVal(doc);
      }
      public double doubleVal(int doc) {
        return (double)floatVal(doc);
      }
      public String strVal(int doc) {
        return Float.toString(floatVal(doc));
      }
      public String toString(int doc) {
    return "max(" + vals.toString(doc) + "," + fval + ")";
      }
    };
  }

  @Override
  public void createWeight(Map context, Searcher searcher) throws IOException {
    source.createWeight(context, searcher);
  }

// boilerplate methods omitted
}

И соответствующий ValueSourceParser:

public class MinValueSourceParser extends ValueSourceParser {
  public void init(NamedList namedList) {
  }

  public ValueSource parse(FunctionQParser fqp) throws ParseException {
        ValueSource source = fp.parseValueSource();
        float val = fp.parseFloat();
        return new MinFloatFunction(source,val);
  }
}