Solr基于双字段最小值的自定义排序实现问询
Solr 双字段最小值自定义排序实现方案
1. 实现自定义MinValueSource类
该类负责计算两个字段的最小值,并提供对应的排序字段实现:
import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.DoubleDocValues; import org.apache.lucene.search.SortField; import java.io.IOException; import java.util.Map; public class MinValueSource extends ValueSource { private final ValueSource field1; private final ValueSource field2; public MinValueSource(ValueSource field1, ValueSource field2) { this.field1 = field1; this.field2 = field2; } @Override public FunctionValues getValues(Map context, org.apache.lucene.index.LeafReaderContext readerContext) throws IOException { FunctionValues vals1 = field1.getValues(context, readerContext); FunctionValues vals2 = field2.getValues(context, readerContext); return new DoubleDocValues(this) { @Override public double doubleVal(int doc) throws IOException { double val1 = vals1.doubleVal(doc); double val2 = vals2.doubleVal(doc); // 处理空值:此处将空值视为无穷大,可根据业务需求调整逻辑 if (Double.isNaN(val1)) return val2; if (Double.isNaN(val2)) return val1; return Math.min(val1, val2); } }; } @Override public SortField getSortField(boolean reverse) { return new SortField(null, new MinFieldComparatorSource(this), reverse); } @Override public String description() { return "customsort(" + field1.description() + ", " + field2.description() + ")"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MinValueSource that = (MinValueSource) o; return field1.equals(that.field1) && field2.equals(that.field2); } @Override public int hashCode() { int result = field1.hashCode(); result = 31 * result + field2.hashCode(); return result; } }
2. 实现自定义ComparatorSource类
为排序逻辑提供自定义比较器:
import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.search.FieldComparator; import org.apache.lucene.search.FieldComparatorSource; import org.apache.lucene.queries.function.FunctionValues; import java.io.IOException; import java.util.Map; public class MinFieldComparatorSource extends FieldComparatorSource { private final MinValueSource minValueSource; public MinFieldComparatorSource(MinValueSource minValueSource) { this.minValueSource = minValueSource; } @Override public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException { return new FieldComparator.DoubleComparator(numHits, fieldname, false) { private FunctionValues values; @Override public void setNextReader(org.apache.lucene.index.LeafReaderContext context) throws IOException { values = minValueSource.getValues(Map.of(), context); } @Override public int compare(int slot1, int slot2) { double val1 = values.doubleVal(slot1); double val2 = values.doubleVal(slot2); return Double.compare(val1, val2); } @Override public int compareBottom(int doc) throws IOException { double val1 = values.doubleVal(doc); double val2 = bottom; return Double.compare(val1, val2); } @Override public void copy(int slot, int doc) throws IOException { bottom = values.doubleVal(doc); } }; } }
3. 实现ValueSourceParser解析自定义函数
该类负责将查询中的customsort(field1, field2)语法转换为MinValueSource实例:
import org.apache.lucene.queries.function.ValueSource; import org.apache.solr.search.FunctionQParser; import org.apache.solr.search.SyntaxError; import org.apache.solr.search.ValueSourceParser; public class MinValueSourceParser extends ValueSourceParser { @Override public ValueSource parse(FunctionQParser fp) throws SyntaxError { ValueSource field1 = fp.parseValueSource(); ValueSource field2 = fp.parseValueSource(); return new MinValueSource(field1, field2); } }
4. 在Solr配置中注册自定义Parser
编辑solrconfig.xml,添加配置让Solr识别自定义函数:
<valueSourceParser name="customsort" class="com.yourpackage.MinValueSourceParser"/>
注意替换com.yourpackage为实际的Java包路径。
5. 使用示例
查询时直接指定sort参数即可:
sort=customsort(field1, field2) asc
对应文档示例:
- document1: field1=4, field2=6 → 最小值4
- document2: field1=7, field2=5 → 最小值5
- document3: field1=2, field2=9 → 最小值2
排序后结果顺序为:document3 → document1 → document2,完全匹配需求。
内容的提问来源于stack exchange,提问作者Ritesh Kumar
相关产品推荐
相关产品推荐

