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);
}
}