8、搜索排序和搜索过滤(lucene笔记)
程序员文章站
2022-07-09 10:23:05
...
一、搜索排序(工程lucene_analyzer03
)
这里我们使用之前工程中创建索引的一个工具类```FileIndexUtil.java
package cn.itcast.util;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
public class FileIndexUtil {
private static Directory directory = null;
static {
try {
directory = FSDirectory.open(new File(
"E:/myeclipse/Lucene/index"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static Directory getDirectory() {
return directory;
}
// 创建索引
public static void index(boolean hasNew) {
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(
Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
if (hasNew) {
writer.deleteAll();//如果我们要新建索引,那么将之前创建的删除
}
File file = new File("E:/myeclipse/Lucene/somefile");
Document document = null;
for (File f : file.listFiles()) {
document = new Document();
document.add(new Field("content", new FileReader(f)));
document.add(new Field("filename", f.getName(),
Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("path", f.getAbsolutePath(),
Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new NumericField("date", Field.Store.YES, true)
.setLongValue(f.lastModified()));
// 最后我们将字节数转换成kb
document.add(new NumericField("size", Field.Store.YES, true)
.setIntValue((int) (f.length())));
writer.addDocument(document);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
说明:此类是之前我们写的一个创建索引的类。下面再写一个类用于测试排序的类SearchTest.java
package cn.lucene.test;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
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.TopDocs;
import org.apache.lucene.util.Version;
import cn.itcast.util.FileIndexUtil;
public class SearchTest {
private static IndexReader reader;
static {
try {
reader = IndexReader.open(FileIndexUtil.getDirectory());
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public IndexSearcher getSearcher() {
try {
if (reader == null) {
reader = IndexReader.open(FileIndexUtil.getDirectory());
} else {
IndexReader tr = IndexReader.openIfChanged(reader);
if (tr != null) {
reader.close();
reader = tr;
}
}
return new IndexSearcher(reader);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void searcher(String queryStr, Sort sort) {
try {
IndexSearcher searcher = getSearcher();
QueryParser parser = new QueryParser(Version.LUCENE_35, "content",
new StandardAnalyzer(Version.LUCENE_35));
Query query = parser.parse(queryStr);
TopDocs tds = null;
if (sort != null) {
tds = searcher.search(query, 50, sort);
} else {
tds = searcher.search(query, 50);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("id:" + sd.doc + ",评分:" + sd.score + ",名称:"
+ doc.get("filename") + ",路径:" + doc.get("path")
+ ",文件大小:" + doc.get("size") + ",日期:"
+ sdf.format(new Date(Long.valueOf(doc.get("date")))));
}
searcher.close();
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
相关的代码我们在之前已经讲过,下面我们进行排序测试TestAnalyzer.java
:
package cn.lucene.test;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.util.FileIndexUtil;
public class TestAnalyzer {
private SearchTest st;
@Before
public void init(){
st = new SearchTest();
}
//重新创建索引
@Test
public void Index(){
FileIndexUtil.index(true);
}
@Test
public void test01(){
//只要设置了排序,那么评分就没有了
//st.searcher("java", Sort.INDEXORDER);//以序号排序
//st.searcher("java", Sort.RELEVANCE);//通过评分排序
//st.searcher("java", new Sort(new SortField("size", SortField.INT)));//通过文件大小排序
//st.searcher("java", new Sort(new SortField("date", SortField.LONG)));//通过日期排序
//st.searcher("java", new Sort(new SortField("filename", SortField.STRING)));//通过文件名排序,升序
//st.searcher("java", new Sort(new SortField("filename", SortField.STRING, true)));//通过文件名排序,降序
//先按大小排序,再按评分排序
st.searcher("java", new Sort(new SortField("size", SortField.INT), SortField.FIELD_SCORE));
}
}
说明:通过上面的测试代码我们可以看到,lucene
默认有很多排序的规则,只要我们自行设置好便可达到相关排序的目的,当然在后面我们还需要自定义排序规则来达到我们的要求,这里只是入门。
二、搜索过滤
这里我们说三个进行搜索过滤的过滤器,其实前面已经提到,这里作为复习.SearchTest.java
public void searcher(String queryStr, Filter filter){
try {
IndexSearcher searcher = getSearcher();
QueryParser parser = new QueryParser(Version.LUCENE_35, "content",
new StandardAnalyzer(Version.LUCENE_35));
Query query = parser.parse(queryStr);
TopDocs tds = null;
if (filter != null) {
//这里我们使用过滤器
tds = searcher.search(query, filter, 50);
} else {
tds = searcher.search(query, 50);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("id:" + sd.doc + ",评分:" + sd.score + ",名称:"
+ doc.get("filename") + ",路径:" + doc.get("path")
+ ",文件大小:" + doc.get("size") + ",日期:"
+ sdf.format(new Date(Long.valueOf(doc.get("date")))));
}
searcher.close();
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
说明:在这个方法中我们传入的不是排序类,而是过滤器。下面进行测试。
@Test
public void test02(){
//范围搜索,从json.c到json.php的分为内搜索json,最后两个参数表示是前后都是闭区间
Filter tr = new TermRangeFilter("filename", "json.c", "json.php", true, true);
//大小范围搜索
tr = NumericRangeFilter.newIntRange("size", 10, 100, true, true);
//可以通过一个query进行过滤
tr = new QueryWrapperFilter(new WildcardQuery(new Term("filename", "*.c")));
st.searcher("json", tr);
}
说明:这里我们给出了三个过滤器,分别进行名字范围、发笑范围过滤器和一个可以通过Query
进行过滤去过滤器。