Java Lucene定時更新索引

需求:每晚2點開始對所有數(shù)據(jù)建立索引罢猪,其它時間近她,每隔一定的時間更新索引。

經(jīng)過測試膳帕,5000條數(shù)據(jù)建立索引只需600ms粘捎,20000條數(shù)據(jù)約1000ms...幾十萬的數(shù)據(jù)也只需要幾秒。
若根據(jù)初步方案危彩,白天更新數(shù)據(jù)索引只更新新添加或者改動的數(shù)據(jù)攒磨,需要將數(shù)據(jù)庫查出的數(shù)據(jù)于IndexReader中的數(shù)據(jù)進行檢索剔除,此操作耗時較多汤徽。初步測試結(jié)果:5000條數(shù)據(jù)需要50s娩缰;20000條數(shù)據(jù)需要220s...
若有20w條數(shù)據(jù),則光剔除數(shù)據(jù)的時間就需要4h谒府,明顯行不通拼坎。
故還不如直接每次都重建所有索引。
不多說完疫,貼初步方案的代碼888:

package net.lucene.buildindex;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
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.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import com.mongodb.DBObject;
/**
* 創(chuàng)建數(shù)據(jù)索引
*
*[@author](http://weibo.com/n/author)liuyang
*[@version](http://weibo.com/n/version)2015.08.06
*/
public class BuildIndex {
private static String filePath = "C:/Users/365/Desktop/8月/Lucene/buildIndex";
private static String filePathAdd = "C:/Users/365/Desktop/8月/Lucene/buildIndex2";
/**
* 創(chuàng)建索引
*/
public void buildIndex() {
try {
// 如果文件夾不存在演痒,則需要首次創(chuàng)建索引
// 否則,只需增量索引
File file = new File(filePath);
if (!((file.exists()) && (file.listFiles().length > 1))) {
this.firstIndex();
} else {
this.updateIndex();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化索引庫indexWriter 一旦
* indexWriter創(chuàng)建完成趋惨,再改變IndexWriterConfig的配置鸟顺,對indexWriter將不產(chǎn)生影響
*
*[@param](http://weibo.com/n/param)OpenModeType
*[@param](http://weibo.com/n/param)fileURL
*[@return](http://weibo.com/n/return)
*/
private IndexWriter initLucene(OpenMode OpenModeType, String fileURL) {
try {
// 創(chuàng)建分詞器 analyzer
// 對原有句子按照空格進行了分詞 所有的大寫字母都可以能轉(zhuǎn)換為小寫的字母
// 可以去掉一些沒有用處的單詞,例如"is","the","are"等單詞器虾,也刪除了所有的標(biāo)點
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);
// 創(chuàng)建IndexWriterConfig
// Windows系統(tǒng)用SimpleFSDirectory讯嫂,其它系統(tǒng)用NIOFSDirectory
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(
Version.LUCENE_46, analyzer);
indexWriterConfig.setOpenMode(OpenModeType);
// 創(chuàng)建目錄
Directory fileDir = new SimpleFSDirectory(new File(fileURL));
// 創(chuàng)建索引庫
IndexWriter indexWriter = new IndexWriter(fileDir,
indexWriterConfig);
return indexWriter;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 第一次創(chuàng)建索引
*/
private void firstIndex() {
IndexWriter indexWriter = null;
try {
// 獲取數(shù)據(jù)
Getdatas getdatas = new Getdatas();
List results = getdatas.getDatas();
// 若數(shù)據(jù)為空或者不存在,則返回兆沙;否則添加索引
if ((results.size() == 0) || null == results) {
return;
} else {
// 獲取索引庫
indexWriter = this.initLucene(OpenMode.CREATE_OR_APPEND,
filePath);
// 添加Fields
this.addFields(results, indexWriter);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 若第一次打開索引文件需要commint 否則會報no segment*
try {
if (null != indexWriter) {
indexWriter.commit();
indexWriter.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 更新索引 lucene本身不支持更新
*
* 通過刪除索引然后再建立索引來更新
*/
private void updateIndex() {
IndexReader indexReader = null;
IndexWriter indexWriterAdd = null;
try {
// 獲取數(shù)據(jù)
Getdatas getdatas = new Getdatas();
List results = getdatas.getDatas();
File fileAdd = new File(filePathAdd);
// 如果文件夾不存在欧芽,創(chuàng)建
if (!fileAdd.exists()) {
fileAdd.mkdir();
}
// 創(chuàng)建IndexReader
File file = new File(filePath);
Directory dir = FSDirectory.open(file);
indexReader = DirectoryReader.open(dir);
long startTime = System.currentTimeMillis();
// 檢索最新添加的數(shù)據(jù)是否索引
List updateDatas = new ArrayList();
for (DBObject updateData : results) {
// 是否在索引庫 標(biāo)識符
boolean flag = this.isInIndex(updateData.get("_id").toString(),
indexReader);
if (flag) {
// 將不在索引庫的數(shù)據(jù),添加到updateDatas中
updateDatas.add(updateData);
}
}
long endTime = System.currentTimeMillis();
System.out.println("剔除數(shù)據(jù)耗時:" + (endTime - startTime) + "ms");
// 添加索引
if ((updateDatas.size() == 0) || (null == updateDatas)) {
return;
} else {
// indexWriter.deleteAll();
if (!((file.exists()) && (file.listFiles().length > 3))) {
return;
} else if (!((fileAdd.exists()) && (fileAdd.listFiles().length > 3))) {
indexWriterAdd = this.initLucene(OpenMode.CREATE_OR_APPEND,
filePathAdd);
this.addFields(updateDatas, indexWriterAdd);
} else {
indexWriterAdd = this.initLucene(OpenMode.CREATE,
filePathAdd);
this.addFields(updateDatas, indexWriterAdd);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != indexWriterAdd) {
indexWriterAdd.commit();
// indexWriterAdd.close();
}
if (null != indexReader) {
indexReader.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 添加Fields
*
*[@param](http://weibo.com/n/param)results
*[@param](http://weibo.com/n/param)indexWriter
*/
private void addFields(List results, IndexWriter indexWriter) {
try {
long startTime = System.currentTimeMillis();
for (int i = 0; i < results.size(); i++) {
// 創(chuàng)建Document
Document doc = new Document();
// 創(chuàng)建Field
Field idField = new StringField("_id", results.get(i).toMap()
.get("_id").toString(), Store.YES);
Field countdateField = new StringField("countdate", results
.get(i).toMap().get("countdate").toString(), Store.YES);
Field averpriceField = new LongField("averprice",
(Long) results.get(i).toMap().get("averprice"),
Store.YES);
Field countField = new IntField("count", (Integer) results
.get(i).toMap().get("count"), Store.YES);
Field appField = new StringField("app", results.get(i).toMap()
.get("app").toString(), Store.YES);
// 添加索引
doc.add(idField);
doc.add(countdateField);
doc.add(averpriceField);
doc.add(countField);
doc.add(appField);
// 將索引添加到實時中去
indexWriter.addDocument(doc);
}
long endTime = System.currentTimeMillis();
System.out.println("創(chuàng)建索引耗時:" + (endTime - startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 若第一次打開索引文件需要commint 否則會報no segment*
try {
if (null != indexWriter) {
indexWriter.commit();
// indexWriter.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 檢查數(shù)據(jù)是否在索引庫中
*
*[@param](http://weibo.com/n/param)id
*[@param](http://weibo.com/n/param)p_indexReader
*[@return](http://weibo.com/n/return)
*/
private boolean isInIndex(String id, IndexReader p_indexReader) {
boolean flag = true;
try {
for (int i = 0; i < p_indexReader.numDocs(); i++) {
Document doc = p_indexReader.document(i);
if (id.equals(doc.get("_id"))) {
flag = false;
return flag;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 查詢
*/
public void search(String path) {
IndexReader indexReader2 = null;
try {
File file = new File(path);
if (!((file.exists()) && (file.listFiles().length < 2))) {
Directory dir = FSDirectory.open(new File(path));
indexReader2 = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(indexReader2);
TermQuery query = new TermQuery(new Term("app", "test1"));
TopDocs hits = searcher.search(query, 10000);
System.out
.println("total " + indexReader2.maxDoc() + " datas!");
// for (ScoreDoc scoreDoc : hits.scoreDocs) {
// Document doc = searcher.doc(scoreDoc.doc);
// System.out.println("_id:" + doc.get("_id") +
// "----countdate:"
// + doc.get("countdate") + "----averprice:"
// + doc.get("averprice") + "----count:"
// + doc.get("count") + "----app:" + doc.get("app"));
// }
System.out.println("find " + hits.scoreDocs.length
+ " results!");
} else {
return;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != indexReader2) {
indexReader2.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葛圃,一起剝皮案震驚了整個濱河市千扔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌库正,老刑警劉巖曲楚,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異褥符,居然都是意外死亡龙誊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門喷楣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來趟大,“玉大人鹤树,你說我怎么就攤上這事⊙沸啵” “怎么了罕伯?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叽讳。 經(jīng)常有香客問我追他,道長,這世上最難降的妖魔是什么绽榛? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任湿酸,我火速辦了婚禮,結(jié)果婚禮上灭美,老公的妹妹穿的比我還像新娘推溃。我一直安慰自己,他們只是感情好届腐,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布铁坎。 她就那樣靜靜地躺著,像睡著了一般犁苏。 火紅的嫁衣襯著肌膚如雪硬萍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天围详,我揣著相機與錄音朴乖,去河邊找鬼。 笑死助赞,一個胖子當(dāng)著我的面吹牛买羞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雹食,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼畜普,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了群叶?” 一聲冷哼從身側(cè)響起吃挑,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎街立,沒想到半個月后舶衬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡几晤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年约炎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟹瘾。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡圾浅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出憾朴,到底是詐尸還是另有隱情狸捕,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布众雷,位于F島的核電站灸拍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏砾省。R本人自食惡果不足惜鸡岗,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望编兄。 院中可真熱鬧轩性,春花似錦、人聲如沸狠鸳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽件舵。三九已至卸察,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铅祸,已是汗流浹背坑质。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留临梗,地道東北人涡扼。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像夜焦,于是被迫代替她去往敵國和親壳澳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容