Lucene索引建立方法和步驟,lucene索引建立
在全文索引工具中,都是由這樣的三部分組成
1.索引部分
2.分詞部分
3.搜尋部分
----------------------------------
索引建立域選項
----------------------------------
Field.Store.YES或者NO(儲存域選項)
YES:表示會把這個域中的內容完全儲存到檔案中,方便進行還原[對於主鍵,標題可以是這種方式儲存]
NO:表示把這個域的內容不儲存到檔案中,但是可以被索引,此時內容無法完全還原(doc.get())[對於內容而言,沒有必要進行儲存,可以設定為No]
Field.index(索引選項)
Index.ANALYZED:進行分詞和索引,適用於標題,內容等
Index.NOT_ANALYZED:進行索引,但不進行分詞,比如社會安全號碼,姓名,ID等,使用於精確搜尋
Index.ANALYZED_NOT_NORMS:進行分詞但是不儲存norms資訊,這個norms中包含了建立索引的時間和權值(排序)等資訊
Index.NOT_ANALYZED_NOT_NORMS:即不進行分詞也不儲存norms資訊
Index.NO:不進行索引
最佳實務
NOT_ANALYZED_NOT_NORMS Store.YES 標識符(主鍵,檔案名稱),電話號碼,社會安全號碼,姓名,日期
ANALYZED Store.YES 文檔標題和摘要
ANALYZED Store.NO 文檔本文
NO Store.YES 文件類型,資料庫主鍵(不進行索引)
NOT_ANALYZED Store.NO 隱藏關鍵字
索引檔案結構剖析
.fnm儲存著域欄位的資訊
.fdt和.fdx儲存著store=yes的資料
.frq儲存著哪些相同的單詞出現多少次(可用作排序和評級)
.nrm專門用來保持一些評級資訊
.tii和.tis儲存著索引裡面的所有資訊
文檔和域的概念
文檔相當於表中的每一條記錄,域相當於表中的每一個欄位
----------------------------------
索引的刪除與更新
----------------------------------
1.刪除
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
// 參數是一個選項,可以是一個query,也可以是一個term,term是一個精確尋找的值
// 此時刪除的文檔並不會被完全刪除,而是儲存在一個資源回收筒中,可以恢複
writer.deleteDocuments(new Term("id", "1"));
2.恢複刪除
// 使用indexreader恢複
// 將readeronly=false
IndexReader reader = IndexReader.open(directory, false);
reader.undeleteAll();
reader.close();
3.強制移除(清空資源回收筒)
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
// 強制移除資料,清空資源回收筒
// Lucene3.5之前是optimize()方法進行處理,但此方法消耗大量記憶體已經被棄用
writer.forceMergeDeletes();
4.最佳化和合并
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
// 添加了多次索引,可以設定允許的最大段索引,會將索引合并為兩段,這兩段中的被刪除的資料會被情空
// 特別注意:此次不建議使用,會消耗大量的開銷,Lucene會根據情況自動最佳化
writer.forceMerge(2);
5.更新索引
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
/*
* Lucene並沒有提供更新的操作,這裡的更新是兩個操作的合并 先刪除之後再添加
*/
Document doc = new Document();
// 先將文檔id=1的索引刪除,再添加一個新的文檔索引
// 先刪除再代替的工作
writer.updateDocument(new Term("id", "1"), doc);
--------------------------------------------------
lucene索引_加權操作
--------------------------------------------------
通過Map<String, Float> scores = new HashMap<String, Float>();方式進行設定
假設對特定郵箱進行評級
/*
* document.setBoost(float) 設定評級
*/
String et = emails[i].substring(emails[i].lastIndexOf("@") + 1);
//System.out.println(et);
if (scores.containsKey(et)) {
document.setBoost(scores.get(et));
} else {
document.setBoost(0.5f);
}
--------------------------------------------------
對日期和數字進行索引
--------------------------------------------------
private int[] attachs = { 2, 3, 1, 4, 5, 5 };
private Date[] dates = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
dates = new Date[ids.length];
dates[0] = sdf.parse("2015-1-1");
dates[1] = sdf.parse("2015-2-1");
dates[2] = sdf.parse("2015-3-1");
dates[3] = sdf.parse("2015-4-1");
dates[4] = sdf.parse("2015-5-1");
dates[5] = sdf.parse("2015-6-1");
// 為數字添加索引
document.add(new NumericField("attach", Field.Store.YES, true).setIntValue(attachs[i]));
// 給日期添加索引
document.add(new NumericField("date", Field.Store.YES, true).setLongValue(dates[i].getTime()));
1.建立索引代碼
* 一.建立索引 */public void index() {IndexWriter writer = null;try {// 1.建立Directory(索引位置)// 建立記憶體的索引// Directory directory = new RAMDirectory();// 建立自訂的索引位置Directory directory = FSDirectory.open(new File("F:/BaiduYunDownload/Cache/lucune/LuceneExamples/indexdata"));// 2.建立IndexWriter(寫入索引)IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35));// 參數2Analyzer表示建立的分詞器writer = new IndexWriter(directory, conf);// 3.建立Document對象Document document = null;// 4.為Document添加Field(相當於添加些屬性)File fs = new File("F:/BaiduYunDownload/Cache/lucune/LuceneExamples/testdata");// 遍曆所有檔案for (File f : fs.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));// 5.通過IndexWriter添加文檔到索引中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();writer = null;} catch (IOException e) {e.printStackTrace();}}}}
2.對索引進行的增刪改更新操作
/* * 用作專門建立索引的工具 */public class IndexUtil {/* * 假設6個文檔 */private String[] ids = { "1", "2", "3", "4", "5", "6" };private String[] emails = { "aa@qq.com", "bb@sina.com", "cc@163.com","dd@google.com", "ee@baidu.com", "ff@heima.com" };private String[] contents = { "hello boy,i like pingpang", "like boy","xx bye i like swim", "hehe, i like basketball","dd fsfs, i like movie", "hello xxx,i like game" };private int[] attachs = { 2, 3, 1, 4, 5, 5 };private Date[] dates = null;private String[] names = { "lili", "wangwu", "lisi", "jack", "tom", "mark" };// 設定加權mapprivate Map<String, Float> scores = new HashMap<String, Float>();/* * 建立索引 */private Directory directory = null;public IndexUtil() throws Exception {// 建立日期索引時,給日期賦值createDate();// 給Emails加權處理scores.put("sina", 2.0f);scores.put("google", 1.5f);directory = FSDirectory.open(new File("F:/BaiduYunDownload/Cache/lucune/Code/code01/indexdata"));}/* * 給日期屬性初始化 */private void createDate() throws Exception {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");dates = new Date[ids.length];dates[0] = sdf.parse("2015-1-1");dates[1] = sdf.parse("2015-2-1");dates[2] = sdf.parse("2015-3-1");dates[3] = sdf.parse("2015-4-1");dates[4] = sdf.parse("2015-5-1");dates[5] = sdf.parse("2015-6-1");}public void index() {IndexWriter writer = null;try {writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));writer.deleteAll();// 建立documentsDocument document = null;for (int i = 0; i < ids.length; i++) {document = new Document();document.add(new Field("id", ids[i], Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));document.add(new Field("email", emails[i], Field.Store.YES,Field.Index.NOT_ANALYZED)); // 不分詞document.add(new Field("content", contents[i], Field.Store.NO,Field.Index.ANALYZED));document.add(new Field("name", names[i], Field.Store.YES,Field.Index.NOT_ANALYZED));// 為數字添加索引document.add(new NumericField("attach", Field.Store.YES, true).setIntValue(attachs[i]));// 給日期添加索引document.add(new NumericField("date", Field.Store.YES, true).setLongValue(dates[i].getTime()));/* * document.setBoost(float) 設定評級 */String et = emails[i].substring(emails[i].lastIndexOf("@") + 1);// System.out.println(et);if (scores.containsKey(et)) {document.setBoost(scores.get(et));} else {document.setBoost(0.5f);}writer.addDocument(document);}} catch (IOException e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();writer = null;} catch (IOException e) {e.printStackTrace();}}}}/* * 強制最佳化索引(forceMerge()將所有索引都重新最佳化一遍) */public void forceMerge() {IndexWriter writer = null;try {writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));// 強制移除資料,清空資源回收筒// Lucene3.5之前是optimize()方法進行處理,但此方法消耗大量記憶體已經被棄用writer.forceMergeDeletes();} catch (IOException e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();writer = null;} catch (IOException e) {e.printStackTrace();}}}}/* * 手動進行Merge最佳化 */public void merge() {IndexWriter writer = null;try {writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));// 添加了多次索引,可以設定允許的最大段索引,會將索引合并為兩段,這兩段中的被刪除的資料會被情空// 特別注意:此次不建議使用,會消耗大量的開銷,Lucene會根據情況自動最佳化writer.forceMerge(2);} catch (IOException e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();writer = null;} catch (IOException e) {e.printStackTrace();}}}}/* * 恢複索引檔案 */public void undelete() throws Exception {// 使用indexreader恢複// 將readeronly=falseIndexReader reader = IndexReader.open(directory, false);reader.undeleteAll();reader.close();}/* * 刪除索引檔案 */public void deleteIndex() {IndexWriter writer = null;try {writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));// 參數是一個選項,可以是一個query,也可以是一個term,term是一個精確尋找的值// 此時刪除的文檔並不會被完全刪除,而是儲存在一個資源回收筒中,可以恢複writer.deleteDocuments(new Term("id", "1"));} catch (IOException e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();writer = null;} catch (IOException e) {e.printStackTrace();}}}}/* * 更新索引 */public void update() {IndexWriter writer = null;try {writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));/* * Lucene並沒有提供更新的操作,這裡的更新是兩個操作的合并 先刪除之後再添加 */Document doc = new Document();// 先將文檔id=1的索引刪除,再添加一個新的文檔索引// 先刪除再代替的工作writer.updateDocument(new Term("id", "1"), doc);} catch (IOException e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();writer = null;} catch (IOException e) {e.printStackTrace();}}}}/* * 查詢 */public void Query() throws Exception {IndexReader reader = IndexReader.open(directory);// 通過reader可以有效擷取文檔的數量System.out.println("本索引儲存的文檔數:" + reader.numDocs());System.out.println("總文檔數(包括資源回收筒):" + reader.maxDoc());}/* * search */public void Search() {try {IndexReader reader = IndexReader.open(directory);IndexSearcher search = new IndexSearcher(reader);// 精確搜尋TermQuery query = new TermQuery(new Term("content", "like"));TopDocs tds = search.search(query, 10);for (ScoreDoc sd : tds.scoreDocs) {Document doc = search.doc(sd.doc);System.out.println(sd.doc + doc.get("name") + "["+ doc.get("email") + "," + doc.get("id") + ","+ doc.get("attach") + "," + doc.get("date") + "]");}} catch (CorruptIndexException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}