1、Lucene相關java
1.首先導入相關的jar包算法
2.編寫工具類數據庫
主要分爲3步:apache
第一步創建FSDirectory,指定文檔存放的路徑。架構
第二步獲取IndexWriter,經過這個來進行文檔的相關操做。less
第三步進行增刪改查。工具
package com.feng; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.CorruptIndexException; 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.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.TopDocs; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.util.Version; import org.wltea.analyzer.lucene.IKAnalyzer; public class LuceneUtil { public static Version version = Version.LUCENE_35; public static File indexPath = new File("F:/workspace/document"); public static Analyzer analyzer = new IKAnalyzer(); private static FSDirectory fsDirectory; private static void initFSDirectory(){ try { fsDirectory = FSDirectory.open(indexPath); } catch (IOException e) { e.printStackTrace(); } } public static FSDirectory getFSDirectory(){ if(fsDirectory == null) initFSDirectory(); if(!LuceneUtil.indexPath.isDirectory()) LuceneUtil.indexPath.mkdirs(); return fsDirectory; } public static void addDoc(Document doc){ try { IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer); iwc.setOpenMode(OpenMode.CREATE_OR_APPEND); IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc); indexWriter.addDocument(doc); indexWriter.close(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (LockObtainFailedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void updateDoc(String id, Document doc) { try { IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer); iwc.setOpenMode(OpenMode.CREATE_OR_APPEND); IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc); indexWriter.updateDocument(new Term("id", id), doc); indexWriter.close(); }catch (Exception e) { e.printStackTrace(); } } public static void deleteDoc(String id){ try { IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer); iwc.setOpenMode(OpenMode.CREATE_OR_APPEND); IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc); indexWriter.deleteDocuments(new Term("id", id)); indexWriter.close(); }catch (Exception e) { e.printStackTrace(); } } public static List<Document> query(String id, String name, String sex){ try { QueryParser parser = new QueryParser(LuceneUtil.version, "problem", new IKAnalyzer()); parser.setAllowLeadingWildcard(true); String s = ""; if(id != null){ s += "+(id:*"+id+"*)"; } if(name != null) s += "+(name:*"+name+"*)"; if(sex != null) s += "+(sex:*"+sex+"*)"; Query query1 = parser.parse(s); IndexReader r = IndexReader.open(LuceneUtil.getFSDirectory()); IndexSearcher indexSearcher = new IndexSearcher(r); TopDocs docs = indexSearcher.search(query1, 100); int totalHits = docs.totalHits; System.out.println("查詢文檔總數 :"+totalHits); List<Document> result = new ArrayList<Document>(); for (ScoreDoc doc : docs.scoreDocs) { Document document = indexSearcher.doc(doc.doc); result.add(document); } indexSearcher.close(); r.close(); return result; } catch (Exception e) { e.printStackTrace(); } return new ArrayList<Document>(); } }
這裏要注意的是上面IndexWriterConfig.setOpenMode(OpenMode);的方法是指定IndexWriter的操做模式,分別有三種性能
OpenMode.CREATE: 建立或覆蓋
OpenMode.APPEND: 追加
OpenMode.CREATE_OR_APPEND: 若是不存在則建立,不然追加
3.測試學習
Lucene的增刪改查都是以DOCUMENT的形式交互的測試
3.1添加
@org.junit.Test public void add(){ Document doc = new Document(); /** * field的構造屬性 * 1.field的名稱,查詢時就是經過這個名稱來查找 * 2.field的值 * 3.是否存儲該field * 4.是否分詞,是否創建索引 * NOT_ANALYZED_NO_NORMS:不分詞,不創建索引 * NOT_ANALYZED:不分詞,創建索引 */ doc.add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("name", "fengzp", Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field("sex", "man", Field.Store.YES, Field.Index.NOT_ANALYZED)); LuceneUtil.addDoc(doc); }
添加後本地就會生成相應的文件:
3.2查詢
@org.junit.Test public void query(){ List<Document> list = LuceneUtil.query("1", null, null); for(Document document : list){ System.out.println("id : "+document.get("id")); System.out.println("name : "+document.get("name")); System.out.println("sex : "+document.get("sex")); } }
返回結果
3.3更新
@org.junit.Test public void update(){ Document doc = new Document(); doc.add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("name", "fengzp123", Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field("sex", "man123", Field.Store.YES, Field.Index.NOT_ANALYZED)); LuceneUtil.updateDoc("1", doc); }
查詢結果:
3.4刪除
@org.junit.Test public void delete(){ LuceneUtil.deleteDoc("1"); }
查詢結果:
這樣看下來,是否是跟數據庫的操做好類似呢。
3、lucene的查詢詳解
lucene 的搜索至關強大,它提供了不少輔助查詢類,每一個類都繼承自Query類,各自完成一種特殊的查詢,你能夠像搭積木同樣將它們任意組合使用,完成一些複雜操做;另外lucene還提供了Sort類對結果進行排序,提供了Filter類對查詢條件進行限制。你或許會不自覺地拿它跟SQL語句進行比較: 「lucene能執行and、or、order by、where、like ‘%xx%’操做嗎?」回答是:「固然沒問題!」
3.1 各類各樣的Query
下面咱們看看lucene到底容許咱們進行哪些查詢操做:
3.1.1 TermQuery
首先介紹最基本的查詢,若是你想執行一個這樣的查詢:「在content域中包含‘lucene’的document」,那麼你能夠用TermQuery:
Term t = new Term("content", " lucene";
Query query = new TermQuery(t);
3.1.2 BooleanQuery
若是你想這麼查詢:「在content域中包含java或perl的document」,那麼你能夠創建兩個TermQuery並把它們用BooleanQuery鏈接起來:
TermQuery termQuery1 = new TermQuery(new Term("content", "java");
TermQuery termQuery 2 = new TermQuery(new Term("content", "perl");
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD);
booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD);
3.1.3 WildcardQuery
若是你想對某單詞進行通配符查詢,你能夠用WildcardQuery,通配符包括’?’匹配一個任意字符和’*’匹配零個或多個任意字符,例如你搜索’use*’,你可能找到’useful’或者’useless’:
Query query = new WildcardQuery(new Term("content", "use*");
3.1.4 PhraseQuery
你可能對中日關係比較感興趣,想查找‘中’和‘日’捱得比較近(5個字的距離內)的文章,超過這個距離的不予考慮,你能夠:
PhraseQuery query = new PhraseQuery();
query.setSlop(5);
query.add(new Term("content ", 「中」));
query.add(new Term(「content」, 「日」));
那麼它可能搜到「中日合做……」、「中方和日方……」,可是搜不到「中國某高層領導說日本欠扁」。
3.1.5 PrefixQuery
若是你想搜以‘中’開頭的詞語,你能夠用PrefixQuery:
PrefixQuery query = new PrefixQuery(new Term("content ", "中");
3.1.6 FuzzyQuery
FuzzyQuery用來搜索類似的term,使用Levenshtein算法。假設你想搜索跟‘wuzza’類似的詞語,你能夠:
Query query = new FuzzyQuery(new Term("content", "wuzza");
你可能獲得‘fuzzy’和‘wuzzy’。
3.1.7 RangeQuery
另外一個經常使用的Query是RangeQuery,你也許想搜索時間域從20060101到20060130之間的document,你能夠用RangeQuery:
RangeQuery query = new RangeQuery(new Term(「time」, 「20060101」), new Term(「time」, 「20060130」), true);
最後的true表示用閉合區間。
3.2 QueryParser
看了這麼多Query,你可能會問:「不會讓我本身組合各類Query吧,太麻煩了!」固然不會,lucene提供了一種相似於SQL語句的查詢語句,咱們姑且叫它lucene語句,經過它,你能夠把各類查詢一句話搞定,lucene會自動把它們查分紅小塊交給相應Query執行。下面咱們對應每種 Query演示一下:
TermQuery能夠用「field:key」方式,例如「content:lucene」。
BooleanQuery中‘與’用‘+’,‘或’用‘ ’,例如「content:java contenterl」。
WildcardQuery仍然用‘?’和‘*’,例如「content:use*」。
PhraseQuery用‘~’,例如「content:"中日"~5」。
PrefixQuery用‘*’,例如「中*」。
FuzzyQuery用‘~’,例如「content: wuzza ~」。
RangeQuery用‘[]’或‘{}’,前者表示閉區間,後者表示開區間,例如「time:[20060101 TO 20060130]」,注意TO區分大小寫。
你能夠任意組合query string,完成複雜操做,例如「標題或正文包括lucene,而且時間在20060101到20060130之間的文章」能夠表示爲:「+ (title:lucene content:lucene) +time:[20060101 TO 20060130]」。代碼以下:
Directory dir = FSDirectory.getDirectory(PATH, false);
IndexSearcher is = new IndexSearcher(dir);
QueryParser parser = new QueryParser("content", new StandardAnalyzer());
Query query = parser.parse("+(title:lucene content:lucene) +time:[20060101 TO 20060130]";
Hits hits = is.search(query);
for (int i = 0; i < hits.length(); i++)
{
Document doc = hits.doc(i);
System.out.println(doc.get("title");
}
is.close();
首先咱們建立一個在指定文件目錄上的IndexSearcher。
而後建立一個使用StandardAnalyzer做爲分析器的QueryParser,它默認搜索的域是content。
接着咱們用QueryParser來parse查詢字串,生成一個Query。
而後利用這個Query去查找結果,結果以Hits的形式返回。
這個Hits對象包含一個列表,咱們挨個把它的內容顯示出來
3.3 排序:Sort 有時你想要一個排好序的結果集,就像SQL語句的「order by」,lucene能作到:經過Sort。 Sort sort = new Sort(「time」); //至關於SQL的「order by time」 Sort sort = new Sort(「time」, true); // 至關於SQL的「order by time desc」