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