lucene 搜尋功能介紹(1)
首先使用搜索功能前需要先建立索引:
/**
* 建立索引
* @author 王晨
*
*/
public class Indexer {
private IndexWriter writer; //寫索引例項
/**
* 構造方法 傳入索引所在的資料夾
* @param indexDir
*/
public Indexer(String indexDir) throws Exception{
Directory dir = FSDirectory.open(Paths.get(indexDir)); //獲取到索引所在的檔案路徑
IndexWriterConfig conf = new IndexWriterConfig(analyzer);
writer = new IndexWriter(dir,conf);
}
/**
* 關閉寫索引(像流一樣需要關閉)
* @throws Exception
*/
public void close() throws Exception{
writer.close();
}
/**
* 對每個檔案進行遍歷 一個一個的索引 (索引指定目錄中的檔案)
* @return
* @throws Exception
*/
public int index(String indexDir) throws Exception{
File[] files = new File(indexDir).listFiles(); //獲取到當前目錄下的所有檔案
for(File file : files){
indexFile(file);
}
return writer.numDocs(); //返回索引的檔案個數
}
/**
* 索引指定檔案
* @param file
* @throws Exception
private void indexFile(File file) throws Exception{
// TODO Auto-generated method stub
System.out.println("當前索引的檔案:"+file.getCanonicalPath());
Document doc = getDocument(file);
writer.addDocument(doc);
}
//獲取文件 文件裡在設定每個欄位 文件中每一行為一個document
/**
* 獲取文件
* @param file
* @return
* @throws Exception
*/
private Document getDocument(File file) throws Exception{
// TODO Auto-generated method stub
Document doc = new Document();
doc.add(new TextField("contents", new FileReader(file)));
doc.add(new TextField("filename", file.getName(), Field.Store.YES)); //將檔名加入到索引中
doc.add(new TextField("fullPath", file.getCanonicalPath(), Field.Store.YES));
return doc;
}
public static void main(String[] args) {
String indexDir = "D:\\lucene";
String dataDir = "D:\\lucene\\data";
Indexer indexer = null;
int numIndexed = 0;
long start = System.currentTimeMillis();
long end = 0;
try {
indexer = new Indexer(indexDir); //輸出索引的目錄
numIndexed = indexer.index(dataDir); //構建索引 返回構建索引的個數
end = System.currentTimeMillis();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
indexer.close();
System.out.println("索引了的檔案個數"+numIndexed+"一共花費了時間"+(end-start)+"毫秒");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
搜尋功能的實現 使用兩種方法 對特定的項進行搜尋 或 使用查詢表示式QueryParser
①準備工作
private Directory dir; private IndexReader reader; private IndexSearcher is;@Before public void setUp() throws Exception { dir = FSDirectory.open(Paths.get("D:\\lucene")); //索引所在的目錄 reader = DirectoryReader.open(dir); //讀取索引 is = new IndexSearcher(reader); }
@After public void tearDown() throws Exception { reader.close(); }
首先介紹對特定的項進行搜尋 (此方法並不常用)TermQuery
/**
* termQuery 查詢 對特定項進行搜尋 必須完全匹配才會查出來
* @throws Exception
*/
@Test
public void testTermQuery() throws Exception{
String searchField = "contents"; //在哪個欄位查詢
String str = "java"; //使用者要查詢的欄位
Term t = new Term(searchField, str);
Query query = new TermQuery(t);
TopDocs hits = is.search(query, 10);
for(ScoreDoc scoreDoc : hits.scoreDocs){
Document document = is.doc(scoreDoc.doc);
System.out.println(document.get("fullPath"));
}
}
使用解析查詢表示式進行搜尋 QueryParser
/**
* 解析查詢表示式 queryParser 若需要兩個欄位匹配其中的一個使用空格空開即可 兩個都匹配使用AND連線 使用~可以通用匹配 particula~
* @throws Exception
*/
@Test
public void testQueryParser() throws Exception{
Analyzer analyzer = new StandardAnalyzer(); //標準分詞器
String searchField = "contents";
String str = "TermQuery"; // java AND php jav~ java php
QueryParser parser = new QueryParser(searchField,analyzer); //查詢解析
Query query = parser.parse(str);
TopDocs hits = is.search(query, 10);
System.out.println("匹配 "+str+" 共有"+hits.totalHits+"個記錄");
for(ScoreDoc scoreDoc : hits.scoreDocs){
Document doc = is.doc(scoreDoc.doc);
System.out.println(doc.get("fullPath"));
}
}
如有需要使用分頁的功能 比如需要分10頁 每頁10條有兩種實現方法:由於lucene沒有提供分頁的功能。
①使用is.search()查詢出100條資料,放在記憶體當中比如放在list裡面 每次點選下一頁返回
不同的資料
②使用is.search()查詢出100條資料,每次點選重新的獲取到100條資料 在for迴圈中返回不同的資料
推薦使用第二種方法:is.search()每次查詢速度很快。而且當併發量很大時 全部存在記憶體當中 會對記憶體造成很大的壓力 容易出現問題。