出处:http://ronxin999.blog.163.com/blog/static/42217920201110532554485/
luence 和solr排序都有排序功能,solr的排序就是基于luence的排序来实现的。solr通过url里加solr=true来排序,把后面带的参数封装成SortField,然后根据luence的底层来排序。下面开始讲luence排序的实现。
luence排序是基于luence有一个最小堆PriorityQueue,PriorityQueue最小堆的比较规则,由子类实现,即lessThan方法。
Luence的FieldValueHitQueue继承了PriorityQueue,我们排序的时候,有可能是根据一个field或者是多个field来排序。
那luence对应的FieldValueHitQueue有两个子类,分别是OneComparatorFieldValueHitQueue和MultiComparatorsFieldValueHitQueue,就是如果按一个Field排序和多个Field的比较方法不一样。分别如下:
//一个field排序的比较方法。
@Override
protected boolean lessThan(final Entry hitA, final Entry hitB) {
assert hitA != hitB;
assert hitA.slot != hitB.slot;
final int c = oneReverseMul * comparator.compare(hitA.slot, hitB.slot);
if (c != 0) {
return c > 0;
}
// avoid random sort order that could lead to duplicates (bug #31241):
return hitA.doc > hitB.doc;
}
//多个field排序的比较方法。
@Override
protected boolean lessThan(final Entry hitA, final Entry hitB) {
assert hitA != hitB;
assert hitA.slot != hitB.slot;
int numComparators = comparators.length;
for (int i = 0; i < numComparators; ++i) {
final int c = reverseMul[i] * comparators[i].compare(hitA.slot, hitB.slot);
if (c != 0) {
// Short circuit
return c > 0;
}
}
// avoid random sort order that could lead to duplicates (bug #31241):
return hitA.doc > hitB.doc;
}
先讲下comparators和reverseMul:
comparators: 是一个数组,如果是当个Field,就是给comparators[0] = field.getComparator(size, 0);即根据不同Field不同的数据类型创建不同的比较器。如果是多个Field,则为每个Field创建一个比较器。
reverseMul:决定按升序还是降序。
从上面两个方法可以看出,如果是多个Field排序,如果第一个Field比较的结果不相等,则按第一Field决定,不会再比较后面的Field,如果第一个Field的值相等,则按后面的Field比较。如果都相等,则按docID的大小来比较。
比较器比较的肯定是要排序Field的值,那Field的值是在什么时候取到的呢,这就是比较器FieldComparator有一个setNextReader的方法。这个方法在Iuence的IndexSearch的search方法里回调用。代码如下:
//这里说明下,collector,如果有排序,collector为TopFieldCollector。
for (int i = 0; i < subReaders.length; i++) { // search each subreader
collector.setNextReader(subReaders[i], docStarts[i]);
Scorer scorer = weight.scorer(subReaders[i], !collector.acceptsDocsOutOfOrder(), true);
if (scorer != null) {
scorer.score(collector);
}
}
而TopFieldCollector的内部子类多个Field的排序的代码为:
@Override
public void setNextReader(IndexReader reader, int docBase) throws IOException {
this.docBase = docBase;
for (int i = 0; i < comparators.length; i++) {
comparators[i].setNextReader(reader, docBase);
}
}
从上面可以看出,其实是比较器FieldComparator的setNextReader方法。FieldComparator的方法就是通过FieldCache的实现类FieldCacheImpl去取对应Field的值,如果没有,则通过Reader去索引库取,然后放到FieldCache缓存。
根据Solr源码发现,solr对排序段Field是有要求的,主要有两点:
1 field必须是索引的field。
2 field不能是multivalued 多个值的。
代码如下:
Solr在获取排序field时,会调用SchemaField的这个方法:
public void checkSortability() throws SolrException {
if (! indexed() ) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"can not sort on unindexed field: "
+ getName());
}
if ( multiValued() ) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"can not sort on multivalued field: "
+ getName());
}
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/zhufenglonglove/article/details/51841217
内容来源于网络,如有侵权,请联系作者删除!