1. 程式人生 > >lucene學習之建立自定義排序

lucene學習之建立自定義排序

Lucene提供了一套強大的API來幫助我們實現自定義排序,本節我們使用一個距離搜尋的例子來闡述:
其實核心是換一個comparator就成,而這個排序器用在哪裡呢,如下所示:

package custom;

import java.io.IOException;

import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;

public class DistanceComparatorSource extends FieldComparatorSource {
    private
int x; private int y; public DistanceComparatorSource(int x,int y){ this.x = x; this.y = y; } @Override public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {//lucene所跟蹤的佇列
return new DistanceSourceLookupComparHor(fieldname, num` its,x,y); } } package custom; import java.io.IOException; import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.SimpleFieldComparator; import org.apache.lucene.util.BytesRef; public
class DistanceSourceLookupComparator extends SimpleFieldComparator<String> { private float[] values; private float top; private float bottom; private String fieldName; private int x; private int y; private BinaryDocValues binaryDocValues; public DistanceSourceLookupComparator(String fieldName, int numHits, int x, int y) { values = new float[numHits]; this.fieldName = fieldName; this.x = x; this.y = y; } @Override public int compare(int slot1, int slot2) { if (values[slot1] > values[slot2]) { return 1; } if (values[slot1] < values[slot2]) { return -1; } return 0; } private float getDistance(int doc) { BytesRef bytesRef = binaryDocValues.get(doc); String xy = bytesRef.utf8ToString(); String[] array = xy.split(","); int deltax = Integer.parseInt(array[0]) - x; int deltay = Integer.parseInt(array[1]) - y; float distance = (float) Math.sqrt(deltax * deltax + deltay * deltay); //System.out.println(distance); return distance; } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { binaryDocValues = context.reader().getBinaryDocValues(fieldName); } public void setBottom(int slot) { bottom = values[slot]; }//設定底部slot public int compareBottom(int doc) throws IOException {//與佇列中命中結果評分最低的比較 float distance = getDistance(doc); if (bottom < distance) { return -1; } if (bottom > distance) { return 1; } return 0; } public int compareTop(int doc) throws IOException { float distance = getDistance(doc); if (top < distance) { return -1; } if (top > distance) { return 1; } return 0; } public void copy(int slot, int doc) throws IOException {//新的命中結果拷貝至佇列中 values[slot] = getDistance(doc); } @Override public void setTopValue(String value) { top = Float.valueOf(value); } @Override public String value(int slot) {// return values[slot] + ""; } } package custom; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.BinaryDocValuesField; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopFieldDocs; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.BytesRef; public class CustomSortTest { public static void main(String[] args) throws Exception { RAMDirectory directory = new RAMDirectory(); Analyzer analyzer = new StandardAnalyzer(); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); addPoint(indexWriter, "El charro", "restaurant", 1, 2); addPoint(indexWriter, "Cafe Poca Cosa", "restaurant", 5, 9); addPoint(indexWriter, "Los Betos", "restaurant", 9, 6); addPoint(indexWriter, "Nico's Toco Shop", "restaurant", 3, 8); indexWriter.close(); IndexReader reader = DirectoryReader.open(directory); IndexSearcher searcher = new IndexSearcher(reader); Query query = new TermQuery(new Term("type","restaurant")); //使用過載後的排序類建構函式 Sort sort = new Sort(new SortField("location",new DistanceComparatorSource(10, 10))); TopFieldDocs topDocs = searcher.search(query, null, Integer.MAX_VALUE,sort,true,false); ScoreDoc[] docs = topDocs.scoreDocs; for(ScoreDoc doc : docs){ Document document = searcher.doc(doc.doc); System.out.println(document.get("name") + ":" + doc.score); } } private static void addPoint(IndexWriter writer,String name,String type,int x,int y) throws Exception{ Document document = new Document(); String xy = x + "," + y; document.add(new Field("name",name,Field.Store.YES,Field.Index.NOT_ANALYZED)); document.add(new Field("type",type,Field.Store.YES,Field.Index.NOT_ANALYZED)); document.add(new Field("location",xy,Field.Store.YES,Field.Index.NOT_ANALYZED)); document.add(new BinaryDocValuesField("location", new BytesRef(xy.getBytes()))); writer.addDocument(document); } }