亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Lucence3.0學(xué)習(xí)

系統(tǒng) 2060 0

?

?

?

官網(wǎng): ??? http://lucene.apache.org/

?lucene中國(guó): ?? lucene.com.cn

?

?

1. 簡(jiǎn)介

??Lucene apache 軟件基金會(huì) 4 jakarta 項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開(kāi)放源代碼的全文檢索引擎工具包,即它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),

? 提供了 ? 完整的查詢(xún)引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語(yǔ)言)。 Lucene 的目的是為軟件開(kāi)發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)

? 全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。

2. 下載

? ? http://labs.renren.com/apache-mirror//lucene/java/3.0.3/

3. 測(cè)試

? eclipse 中邪見(jiàn)項(xiàng)目 Lucence3.0Test, 將一下包導(dǎo)入到 build 路徑中

? ? ?lucene-core-3.0.2.jar

? ? ?lucene-demos-3.0.2.jar

? ? lucene-analyzers-3.0.2.jar

? ? lucene-fast-vector-highlighter-3.0.2.jar

? ? lucene-highlighter-3.0.2.jar

? ? lucene-memory-3.0.2.jar

? ? 在任意目錄下新建兩個(gè)文件夾:

? ? 用來(lái)存放 lucence 進(jìn)行分詞的文件和生成的 index 。如下圖: file1 用來(lái)存放進(jìn)行分詞的文件,里面存放有 N 個(gè) txt 文件, txt 文件的內(nèi)容任意,如:我們都是中國(guó)人, index 文件夾是新建的,里面不要有任何的文件,是用來(lái)存儲(chǔ)生成的 index

? ? http://pic002.cnblogs.com/images/2011/310459/2011071621303710.jpg

4. 代碼

? ? 新建創(chuàng)建索引的類(lèi),以及測(cè)試

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class IndexerOK {
private static String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index"; // 索引存放目錄
private static String DATA_DIR = "D:\\nutchwork\\LucenceTestDir\\file1"; // 小文件存放的目錄

public static void main(String[] args) throws Exception {

??
long start = new Date().getTime();
??
int numIndexed = index( new File(INDEX_DIR), new File(DATA_DIR)); // 調(diào)用 index 方法
?? long end = new Date().getTime();
?? System.out.println("Indexing " + numIndexed + " files took "
???? + (end - start) + " milliseconds");
}

/**
*
索引 dataDir 下的 .txt 文件,并儲(chǔ)存在 indexDir 下,返回索引的文件數(shù)量
*
*
@param indexDir
*
@param dataDir
*
@return int
*
@throws IOException
*/

public static int index(File indexDir, File dataDir) throws IOException {

??
if (!dataDir.exists() || !dataDir.isDirectory()) {
???
throw new IOException(dataDir
????? + " does not exist or is not a directory");
?? }
?? Analyzer analyzer =
new IKAnalyzer(); // 采用的分詞器

?? //
第三個(gè)參數(shù) 為 true 表示新建, false 表示添加到原有索引中
?? IndexWriter writer = new IndexWriter(FSDirectory.open(indexDir),
???? analyzer,
true , IndexWriter.MaxFieldLength.LIMITED);

?? indexDirectory(writer, dataDir);
// 調(diào)用 indexDirectory 方法
?? int numIndexed = writer.numDocs();
?? writer.optimize();
?? writer.close();
??
return numIndexed;
}

/**
*
循環(huán)遍歷目錄下的所有 .txt 文件并進(jìn)行索引
*
*
@param writer
*
@param dir
*
@throws IOException
*/

private static void indexDirectory(IndexWriter writer, File dir)
???
throws IOException {

?? File[] files = dir.listFiles();

??
for ( int i = 0; i < files.length; i++) {
??? File f = files[i];
???
if (f.isDirectory()) {
???? indexDirectory(writer, f);
// recurse
??? } else if (f.getName().endsWith(".txt")) {
???? indexFile(writer, f);
??? }
?? }
}

/**
*
對(duì)單個(gè) txt 文件進(jìn)行索引
*
*
@param writer
*
@param f
*
@throws IOException
*/

private static void indexFile(IndexWriter writer, File f)
???
throws IOException {

??
if (f.isHidden() || !f.exists() || !f.canRead()) {
???
return ;
?? }

?? System.out.println("Indexing " + f.getCanonicalPath());

?? Document doc =
new Document();
??
// doc.add(new Field("contents", new FileReader(f)));
?? doc.add( new Field("filename", f.getCanonicalPath(), Field.Store.YES, Field.Index.ANALYZED));

?? String temp = FileReaderAll(f.getCanonicalPath(), "GBK");
?? System.out.println(temp);

?? doc.add(
new Field("TTT", temp, Field.Store.YES, Field.Index.ANALYZED));

?? doc.add(
new Field("path", f.getPath(), Field.Store.YES,
???? Field.Index.ANALYZED));

?? doc.add(
new Field("modified", DateTools.timeToString(f.lastModified(),
???? DateTools.Resolution.MINUTE), Field.Store.YES,
???? Field.Index.ANALYZED));

?? FileInputStream fis =
new FileInputStream(f);
??
// 按照 UTF-8 編碼方式將字節(jié)流轉(zhuǎn)化為字符流
?? InputStreamReader isr = new InputStreamReader(fis, "utf-8");
??
// 從字符流中獲取文本并進(jìn)行緩沖
?? BufferedReader br = new BufferedReader(isr);

?? doc.add(
new Field("contents", br));

?? writer.setUseCompoundFile(
false );
?? writer.addDocument(doc);
}

public static String FileReaderAll(String FileName, String charset)
???
throws IOException {
?? BufferedReader reader =
new BufferedReader( new InputStreamReader(
????
new FileInputStream(FileName), charset));
?? String line =
new String();
?? String temp =
new String();

??
while ((line = reader.readLine()) != null ) {
??? temp += line;
?? }
?? reader.close();
??
return temp;
}

}

復(fù)制代碼

  運(yùn)行結(jié)果:

? ? ??

Indexing D:\nutchwork\LucenceTestDir\file1\1.txt
我們是中國(guó)人
Indexing D:\nutchwork\LucenceTestDir\file1\2.txt
我們是中國(guó)人
Indexing D:\nutchwork\LucenceTestDir\file1\3.txt
我們是中國(guó)人
Indexing D:\nutchwork\LucenceTestDir\file1\4.txt
我們是中國(guó)人
Indexing 4 files took 2293 milliseconds

復(fù)制代碼

  新建查詢(xún)的類(lèi)以及測(cè)試:

? ?

import java.io.File;
import java.io.StringReader;
import java.util.Date;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable;
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.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKQueryParser;
import org.wltea.analyzer.lucene.IKSimilarity;

public class SearchQueryOK {
private static String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index"; // 索引所在的路徑
private static String KEYWORD = " 中國(guó)人 "; // 關(guān)鍵詞
private static int TOP_NUM = 100; // 顯示前 100 條結(jié)果

public static void main(String[] args) throws Exception {
?? File indexDir =
new File(INDEX_DIR);
??
if (!indexDir.exists() || !indexDir.isDirectory()) {
???
throw new Exception(indexDir
????? + " does not exist or is not a directory.");
?? }
?? search(indexDir, KEYWORD);
// 調(diào)用 search 方法進(jìn)行查詢(xún)
}

/**
*
查詢(xún)
*
*
@param indexDir
*
@param q
*
@throws Exception
*/

public static void search(File indexDir, String q) throws Exception {
?? IndexSearcher is =
new IndexSearcher(FSDirectory.open(indexDir), true ); // read-only
?? String[] field = {"TTT","modified","filename"};
??
long start = new Date().getTime(); // start time

?? //
高亮設(shè)置
?? Analyzer analyzer = new IKAnalyzer(); // 設(shè)定分詞器
?? Query query2 = IKQueryParser.parseMultiField(field, KEYWORD);
??
??
??
// 實(shí)例化搜索器
?? IndexSearcher isearcher1 = new IndexSearcher(FSDirectory.open(indexDir));
??
// 在索引器中使用 IKSimilarity 相似度評(píng)估器
??
?? isearcher1.setSimilarity(
new IKSimilarity());
?
??
??
??
?? Sort sort =
new Sort( new SortField("path", SortField.DOC, false ));
??
//TermQuery q1 = new TermQuery(new Term("filename", "1"));
?? //
搜索相似度最高的記錄
?? TopDocs topDocs1 = isearcher1.search(query2, null , TOP_NUM,sort);
?
?? ScoreDoc[] hits3 = topDocs1.scoreDocs;
?? SimpleHTMLFormatter simpleHtmlFormatter =
new SimpleHTMLFormatter(
???? "<span style='color:#ff0000'>", "</span>");
// 設(shè)定高亮顯示的格式,也就是對(duì)高亮顯示的詞組加上前綴后綴
?? Highlighter highlighter = new Highlighter(simpleHtmlFormatter,
????
new QueryScorer(query2));
??
for ( int i = 0; i < hits3.length; i++) {
??? Document doc = is.doc(hits3[i].doc);
??? String docTTT = doc.get("TTT");
??? highlighter.setTextFragmenter(
new SimpleFragmenter(docTTT.length())); // 設(shè)置每次返回的字符數(shù) . 想必大家在使用搜索引擎的時(shí)候也沒(méi)有一并把全部數(shù)據(jù)展示出來(lái)吧,當(dāng)然這里也是設(shè)定只展示部分?jǐn)?shù)據(jù)
??? TokenStream tokenStream = analyzer.tokenStream("",
?????
new StringReader(docTTT));
??? String str = highlighter.getBestFragment(tokenStream, docTTT);
??? System.out.println("
高亮設(shè)置 : " + str );
??
??? String docModified = doc.get("filename");
??? highlighter.setTextFragmenter(
new SimpleFragmenter(docModified.length()));
??
??? TokenStream tokenStream2 = analyzer.tokenStream("",
?????
new StringReader(docModified));
??? String str2 = highlighter.getBestFragment(tokenStream2, docModified);
??? System.out.println("
高亮設(shè)置 : " + str2 );
??
? ??
???
???
??? List<Fieldable> list = doc.getFields();
???
for ( int j = 0; j < list.size(); j++) {
???? Fieldable fieldable = list.get(j);
???? System.out.println(fieldable.name() + " : "
?????? + fieldable.stringValue() + "<br>");
??? }
?? }

??
??
? ?
??
??
long end = new Date().getTime(); // end time

?? System.out.println("Found " + hits3.length
???? + " document(s) (in " + (end - start)
???? + " milliseconds) that matched query '" + q + "':");
}

}

復(fù)制代碼

  對(duì)索引的操作類(lèi):

? ??

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

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.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class ManageIndexFile {
private static String INDEX_DIR = "D:\\nutchwork\\LucenceTestDir\\index"; // 索引存放目錄


//
刪除索引
public static void DeleteIndex(SearchDocBean bean) throws IOException {
?? Directory dir = FSDirectory.open(
new File(INDEX_DIR));
?? IndexReader reader = IndexReader.open(dir,
false );
?? Term term =
new Term("modified", bean.getId());
??
int count = reader.deleteDocuments(term);
?? reader.close();
?? System.out.println("Successful Delete " + count + " path==" + bean.getId());

}

public static void DeleteIndex( int [] posIDS) throws IOException {
?? Directory dir = FSDirectory.open(
new File(INDEX_DIR));
?? IndexReader reader = IndexReader.open(dir,
false );
??
for ( int i = 0; i < posIDS.length; i++) {
??? Term term =
new Term("posID", Integer.toString(posIDS[i]));
??? reader.deleteDocuments(term);
?? }
?? reader.close();

}
// 更新索引
public static void UpdateIndex(SearchDocBean bean) throws IOException {
?? Directory dir = FSDirectory.open(
new File(INDEX_DIR));
?? IndexReader reader = IndexReader.open(dir,
false );
?? Term term =
new Term("modified", bean.getId());
?? reader.deleteDocuments(term);
?? reader.close();

?? IndexWriter writer =
new IndexWriter(FSDirectory.open( new File(
???? INDEX_DIR)),
new StandardAnalyzer(Version.LUCENE_CURRENT),
????
true , IndexWriter.MaxFieldLength.LIMITED);
?? Document doc =
new Document();

?? doc.add(
new Field("modified", bean.getId(), Field.Store.YES,
???? Field.Index.NOT_ANALYZED));
?? writer.addDocument(doc);
?? writer.optimize();
?? writer.close();

}



// 增加索引
public static void AddIndex(SearchDocBean bean,
??? Connection conn)
throws IOException, SQLException {
?? Analyzer analyzer =
new IKAnalyzer(); // 采用的分詞器

?? IndexWriter writer =
new IndexWriter(FSDirectory.open( new File(
???? INDEX_DIR)), analyzer,
false ,
???? IndexWriter.MaxFieldLength.LIMITED);

?? Document doc =
new Document();
?? doc.add(
new Field("filename", bean.getFileName(), Field.Store.YES,
???? Field.Index.ANALYZED));

?? doc.add(
new Field("path", bean.getPath(), Field.Store.YES,
???? Field.Index.ANALYZED));

?? doc.add(
new Field("dateTime", bean.getId(), Field.Store.YES,
???? Field.Index.ANALYZED));

?? doc.add(
new Field("TTT", bean.getContents(), Field.Store.YES, Field.Index.ANALYZED));

?? writer.setUseCompoundFile(
false );
?? writer.addDocument(doc);
?? writer.optimize();
?? writer.close();
}

}

復(fù)制代碼

  封裝起來(lái)的查詢(xún)結(jié)果:

? ?

public class SearchDocBean {
???
private String id;
???
private String path;
???
private String contents;
???
private String dateTime;
???
public String getId() {
???????
return id;
??? }
???
public void setId(String id) {
???????
this .id = id;
??? }
???
public String getPath() {
???????
return path;
??? }
???
public void setPath(String path) {
???????
this .path = path;
??? }
???
public String getContents() {
???????
return contents;
??? }
???
public void setContents(String contents) {
???????
this .contents = contents;
??? }
???
public String getDateTime() {
???????
return dateTime;
??? }
???
public void setDateTime(String dateTime) {
???????
this .dateTime = dateTime;
??? }
???
public String getFileName() {
???????
return fileName;
??? }
???
public void setFileName(String fileName) {
???????
this .fileName = fileName;
??? }
???
private String fileName;

}

復(fù)制代碼

? ? 下面是 serach 中國(guó)人的 結(jié)果:

? ?

? 高亮設(shè)置 : <span style='color:#ff0000'> 中國(guó)人 </span>
?
高亮設(shè)置 : null
filename : D:\nutchwork\LucenceTestDir\file1\1.txt<br>
TTT :
我們是中國(guó)人 <br>
path : D:\nutchwork\LucenceTestDir\file1\1.txt<br>
modified : 201107161115<br>
?
高亮設(shè)置 : <span style='color:#ff0000'> 中國(guó)人 </span>
?
高亮設(shè)置 : null
filename : D:\nutchwork\LucenceTestDir\file1\2.txt<br>
TTT :
我們是中國(guó)人 <br>
path : D:\nutchwork\LucenceTestDir\file1\2.txt<br>
modified : 201107161115<br>
?
高亮設(shè)置 : <span style='color:#ff0000'> 中國(guó)人 </span>
?
高亮設(shè)置 : null
filename : D:\nutchwork\LucenceTestDir\file1\3.txt<br>
TTT :
我們是中國(guó)人 <br>
path : D:\nutchwork\LucenceTestDir\file1\3.txt<br>
modified : 201107161115<br>
?
高亮設(shè)置 : <span style='color:#ff0000'> 中國(guó)人 </span>
?
高亮設(shè)置 : null
filename : D:\nutchwork\LucenceTestDir\file1\4.txt<br>
TTT :
我們是中國(guó)人 <br>
path : D:\nutchwork\LucenceTestDir\file1\4.txt<br>
modified : 201107161115<br>
Found 4 document(s) (in 717 milliseconds) that matched query '
中國(guó)人 ':

復(fù)制代碼

  整個(gè)工程:基本上是從網(wǎng)上找到的代碼,運(yùn)行了下,算是有一個(gè)大概的了解。

?

?

?

?

?

?

?

Lucene 簡(jiǎn)介

Lucene 是一個(gè)基于 Java 的全文信息檢索工具包,它不是一個(gè)完整的搜索應(yīng)用程序,而是為你的應(yīng)用程序提供索引和搜索功能。 Lucene 目前是 Apache Jakarta 家族中的一個(gè)開(kāi)源項(xiàng)目。也是目前最為流行的基于 Java 開(kāi)源全文檢索工具包。

目前已經(jīng)有很多應(yīng)用程序的搜索功能是基于 Lucene 的,比如 Eclipse 的幫助系統(tǒng)的搜索功能。 Lucene 能夠?yàn)槲谋绢?lèi)型的數(shù)據(jù)建立索引,所以你只要能把你要索引的數(shù)據(jù)格式轉(zhuǎn)化的文本的, Lucene 就能對(duì)你的文檔進(jìn)行索引和搜索。比如你要對(duì)一些 HTML 文檔, PDF 文檔進(jìn)行索引的話你就首先需要把 HTML 文檔和 PDF 文檔轉(zhuǎn)化成文本格式的,然后將轉(zhuǎn)化后的內(nèi)容交給 Lucene 進(jìn)行索引,然后把創(chuàng)建好的索引文件保存到磁盤(pán)或者內(nèi)存中,最后根據(jù)用戶(hù)輸入的查詢(xún)條件在索引文件上進(jìn)行查詢(xún)。不指定要索引的文檔的格式也使 Lucene 能夠幾乎適用于所有的搜索應(yīng)用程序。

1 表示了搜索應(yīng)用程序和 Lucene 之間的關(guān)系,也反映了利用 Lucene 構(gòu)建搜索應(yīng)用程序的流程:


1. 搜索應(yīng)用程序和 Lucene 之間的關(guān)系
圖 1. 搜索應(yīng)用程序和 Lucene 之間的關(guān)系

回頁(yè)首

索引和搜索

索引是現(xiàn)代搜索引擎的核心,建立索引的過(guò)程就是把源數(shù)據(jù)處理成非常方便查詢(xún)的索引文件的過(guò)程。為什么索引這么重要呢,試想你現(xiàn)在要在大量的文 檔中搜索含有某個(gè)關(guān)鍵詞的文檔,那么如果不建立索引的話你就需要把這些文檔順序的讀入內(nèi)存,然后檢查這個(gè)文章中是不是含有要查找的關(guān)鍵詞,這樣的話就會(huì)耗 費(fèi)非常多的時(shí)間,想想搜索引擎可是在毫秒級(jí)的時(shí)間內(nèi)查找出要搜索的結(jié)果的。這就是由于建立了索引的原因,你可以把索引想象成這樣一種數(shù)據(jù)結(jié)構(gòu),他能夠使你 快速的隨機(jī)訪問(wèn)存儲(chǔ)在索引中的關(guān)鍵詞,進(jìn)而找到該關(guān)鍵詞所關(guān)聯(lián)的文檔。 Lucene 采用的是一種稱(chēng)為反向索引( inverted index )的機(jī)制。反向索引就是說(shuō)我們維護(hù)了一個(gè)詞 / 短語(yǔ)表,對(duì)于這個(gè)表中的每個(gè)詞 / 短語(yǔ),都有一個(gè)鏈表描述了有哪些文檔包含了這個(gè)詞 / 短語(yǔ)。這樣在用戶(hù)輸入查詢(xún)條件的時(shí)候,就能非常快的得到搜索結(jié)果。我們將在本系列文章的第二部分詳細(xì)介紹 Lucene 的索引機(jī)制,由于 Lucene 提供了簡(jiǎn)單易用的 API ,所以即使讀者剛開(kāi)始對(duì)全文本進(jìn)行索引的機(jī)制并不太了解,也可以非常容易的使用 Lucene 對(duì)你的文檔實(shí)現(xiàn)索引。

對(duì)文檔建立好索引后,就可以在這些索引上面進(jìn)行搜索了。搜索引擎首先會(huì)對(duì)搜索的關(guān)鍵詞進(jìn)行解析,然后再在建立好的索引上面進(jìn)行查找,最終返回和用戶(hù)輸入的關(guān)鍵詞相關(guān)聯(lián)的文檔。

回頁(yè)首

Lucene 軟件包分析

Lucene 軟件包的發(fā)布形式是一個(gè) JAR 文件,下面我們分析一下這個(gè) JAR 文件里面的主要的 JAVA 包,使讀者對(duì)之有個(gè)初步的了解。

Package: org.apache.lucene.document

這個(gè)包提供了一些為封裝要索引的文檔所需要的類(lèi),比如 Document, Field 。這樣,每一個(gè)文檔最終被封裝成了一個(gè) Document 對(duì)象。

Package: org.apache.lucene.analysis

這個(gè)包主要功能是對(duì)文檔進(jìn)行分詞,因?yàn)槲臋n在建立索引之前必須要進(jìn)行分詞,所以這個(gè)包的作用可以看成是為建立索引做準(zhǔn)備工作。

Package: org.apache.lucene.index

這個(gè)包提供了一些類(lèi)來(lái)協(xié)助創(chuàng)建索引以及對(duì)創(chuàng)建好的索引進(jìn)行更新。這里面有兩個(gè)基礎(chǔ)的類(lèi): IndexWriter IndexReader ,其中 IndexWriter 是用來(lái)創(chuàng)建索引并添加文檔到索引中的, IndexReader 是用來(lái)刪除索引中的文檔的。

Package: org.apache.lucene.search

這個(gè)包提供了對(duì)在建立好的索引上進(jìn)行搜索所需要的類(lèi)。比如 IndexSearcher Hits, IndexSearcher 定義了在指定的索引上進(jìn)行搜索的方法, Hits 用來(lái)保存搜索得到的結(jié)果。

回頁(yè)首

一個(gè)簡(jiǎn)單的搜索應(yīng)用程序

假設(shè)我們的電腦的目錄中含有很多文本文檔,我們需要查找哪些文檔含有某個(gè)關(guān)鍵詞。為了實(shí)現(xiàn)這種功能,我們首先利用 Lucene 對(duì)這個(gè)目錄中的文檔建立索引,然后在建立好的索引中搜索我們所要查找的文檔。通過(guò)這個(gè)例子讀者會(huì)對(duì)如何利用 Lucene 構(gòu)建自己的搜索應(yīng)用程序有個(gè)比較清楚的認(rèn)識(shí)。

回頁(yè)首

建立索引

為了對(duì)文檔進(jìn)行索引, Lucene 提供了五個(gè)基礎(chǔ)的類(lèi),他們分別是 Document, Field, IndexWriter, Analyzer, Directory 。下面我們分別介紹一下這五個(gè)類(lèi)的用途:

Document

Document 是用來(lái)描述文檔的,這里的文檔可以指一個(gè) HTML 頁(yè)面,一封電子郵件,或者是一個(gè)文本文件。一個(gè) Document 對(duì)象由多個(gè) Field 對(duì)象組成的。可以把一個(gè) Document 對(duì)象想象成數(shù)據(jù)庫(kù)中的一個(gè)記錄,而每個(gè) Field 對(duì)象就是記錄的一個(gè)字段。

Field

Field 對(duì)象是用來(lái)描述一個(gè)文檔的某個(gè)屬性的,比如一封電子郵件的標(biāo)題和內(nèi)容可以用兩個(gè) Field 對(duì)象分別描述。

Analyzer

在一個(gè)文檔被索引之前,首先需要對(duì)文檔內(nèi)容進(jìn)行分詞處理,這部分工作就是由 Analyzer 來(lái)做的。 Analyzer 類(lèi)是一個(gè)抽象類(lèi),它有多個(gè)實(shí)現(xiàn)。針對(duì)不同的語(yǔ)言和應(yīng)用需要選擇適合的 Analyzer Analyzer 把分詞后的內(nèi)容交給 IndexWriter 來(lái)建立索引。

IndexWriter

IndexWriter Lucene 用來(lái)創(chuàng)建索引的一個(gè)核心的類(lèi),他的作用是把一個(gè)個(gè)的 Document 對(duì)象加到索引中來(lái)。

Directory

這個(gè)類(lèi)代表了 Lucene 的索引的存儲(chǔ)的位置,這是一個(gè)抽象類(lèi),它目前有兩個(gè)實(shí)現(xiàn),第一個(gè)是 FSDirectory ,它表示一個(gè)存儲(chǔ)在文件系統(tǒng)中的索引的位置。第二個(gè)是 RAMDirectory ,它表示一個(gè)存儲(chǔ)在內(nèi)存當(dāng)中的索引的位置。

熟悉了建立索引所需要的這些類(lèi)后,我們就開(kāi)始對(duì)某個(gè)目錄下面的文本文件建立索引了,清單 1 給出了對(duì)某個(gè)目錄下的文本文件建立索引的源代碼。


清單 1. 對(duì)文本文件建立索引

package TestLucene;

import java.io.File;

import java.io.FileReader;

import java.io.Reader;

import java.util.Date;

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.index.IndexWriter;

/**

* This class demonstrate the process of creating index with Lucene

* for text files

*/

public class TxtFileIndexer {

???? public static void main(String[] args) throws Exception{

???? //indexDir is the directory that hosts Lucene's index files

???? File ?? indexDir = new File("D:\\luceneIndex");

???? //dataDir is the directory that hosts the text files that to be indexed

???? File ?? dataDir ? = new File("D:\\luceneData");

???? Analyzer luceneAnalyzer = new StandardAnalyzer();

???? File[] dataFiles ? = dataDir.listFiles();

???? IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);

???? long startTime = new Date().getTime();

???? for(int i = 0; i < dataFiles.length; i++){

????????? if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){

?????????????? System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());

?????????????? Document document = new Document();

?????????? ???? Reader txtReader = new FileReader(dataFiles[i]);

?????????????? document.add(Field.Text("path",dataFiles[i].getCanonicalPath()));

?????????????? document.add(Field.Text("contents",txtReader));

?????????????? indexWriter.addDocument(document);

???? ????? }

???? }

???? indexWriter.optimize();

???? indexWriter.close();

???? long endTime = new Date().getTime();

???????

???? System.out.println("It takes " + (endTime - startTime)

???????? + " milliseconds to create index for the files in directory "

???????? + dataDir.getPath()); ???????

???? }

}

?

在清單 1 中,我們注意到類(lèi) IndexWriter 的構(gòu)造函數(shù)需要三個(gè)參數(shù),第一個(gè)參數(shù)指定了所創(chuàng)建的索引要存放的位置,他可以是一個(gè) File 對(duì)象,也可以是一個(gè) FSDirectory 對(duì)象或者 RAMDirectory 對(duì)象。第二個(gè)參數(shù)指定了 Analyzer 類(lèi)的一個(gè)實(shí)現(xiàn),也就是指定這個(gè)索引是用哪個(gè)分詞器對(duì)文擋內(nèi)容進(jìn)行分詞。第三個(gè)參數(shù)是一個(gè)布爾型的變量,如果為 true 的話就代表創(chuàng)建一個(gè)新的索引,為 false 的話就代表在原來(lái)索引的基礎(chǔ)上進(jìn)行操作。接著程序遍歷了目錄下面的所有文本文檔,并為每一個(gè)文本文檔創(chuàng)建了一個(gè) Document 對(duì)象。然后把文本文檔的兩個(gè)屬性:路徑和內(nèi)容加入到了兩個(gè) Field 對(duì)象中,接著在把這兩個(gè) Field 對(duì)象加入到 Document 對(duì)象中,最后把這個(gè)文檔用 IndexWriter 類(lèi)的 add 方法加入到索引中去。這樣我們便完成了索引的創(chuàng)建。接下來(lái)我們進(jìn)入在建立好的索引上進(jìn)行搜索的部分。

回頁(yè)首

搜索文檔

利用 Lucene 進(jìn)行搜索就像建立索引一樣也是非常方便的。在上面一部分中,我們已經(jīng)為一個(gè)目錄下的文本文檔建立好了索引,現(xiàn)在我們就要在這個(gè)索引上進(jìn)行搜索以找到包含某 個(gè)關(guān)鍵詞或短語(yǔ)的文檔。 Lucene 提供了幾個(gè)基礎(chǔ)的類(lèi)來(lái)完成這個(gè)過(guò)程,它們分別是呢 IndexSearcher, Term, Query, TermQuery, Hits. 下面我們分別介紹這幾個(gè)類(lèi)的功能。

Query

這是一個(gè)抽象類(lèi),他有多個(gè)實(shí)現(xiàn),比如 TermQuery, BooleanQuery, PrefixQuery. 這個(gè)類(lèi)的目的是把用戶(hù)輸入的查詢(xún)字符串封裝成 Lucene 能夠識(shí)別的 Query

Term

Term 是搜索的基本單位,一個(gè) Term 對(duì)象有兩個(gè) String 類(lèi)型的域組成。生成一個(gè) Term 對(duì)象可以有如下一條語(yǔ)句來(lái)完成: Term term = new Term(“fieldName”,”queryWord”); 其中第一個(gè)參數(shù)代表了要在文檔的哪一個(gè) Field 上進(jìn)行查找,第二個(gè)參數(shù)代表了要查詢(xún)的關(guān)鍵詞。

TermQuery

TermQuery 是抽象類(lèi) Query 的一個(gè)子類(lèi),它同時(shí)也是 Lucene 支持的最為基本的一個(gè)查詢(xún)類(lèi)。生成一個(gè) TermQuery 對(duì)象由如下語(yǔ)句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的構(gòu)造函數(shù)只接受一個(gè)參數(shù),那就是一個(gè) Term 對(duì)象。

IndexSearcher

IndexSearcher 是用來(lái)在建立好的索引上進(jìn)行搜索的。它只能以只讀的方式打開(kāi)一個(gè)索引,所以可以有多個(gè) IndexSearcher 的實(shí)例在一個(gè)索引上進(jìn)行操作。

Hits

Hits 是用來(lái)保存搜索的結(jié)果的。

介紹完這些搜索所必須的類(lèi)之后,我們就開(kāi)始在之前所建立的索引上進(jìn)行搜索了,清單 2 給出了完成搜索功能所需要的代碼。


清單 2 :在建立好的索引上進(jìn)行搜索

? package TestLucene;

? import java.io.File;

? import org.apache.lucene.document.Document;

? import org.apache.lucene.index.Term;

? import org.apache.lucene.search.Hits;

? import org.apache.lucene.search.IndexSearcher;

? import org.apache.lucene.search.TermQuery;

? import org.apache.lucene.store.FSDirectory;

? /**

? * This class is used to demonstrate the

? * process of searching on an existing

? * Lucene index

? *

? */

? public class TxtFileSearcher {

??????? ? public static void main(String[] args) throws Exception{

??????? ??? String queryStr = "lucene";

??????? ??? //This is the directory that hosts the Lucene index

??????? File indexDir = new File("D:\\luceneIndex");

??????? FSDirectory directory = FSDirectory.getDirectory(indexDir,false);

??????? IndexSearcher searcher = new IndexSearcher(directory);

??????? if(!indexDir.exists()){

??????? ?????? ? System.out.println("The Lucene index is not exist");

??????? ?????? ? return;

??????? }

??????? Term term = new Term("contents",queryStr.toLowerCase());

??????? TermQuery luceneQuery = new TermQuery(term);

??????? Hits hits = searcher.search(luceneQuery);

??????? for(int i = 0; i < hits.length(); i++){

??????? ?????? ? Document document = hits.doc(i);

??????? ?????? ? System.out.println("File: " + document.get("path"));

? ?????? }

??????? ? }

? }

?

在清單 2 中,類(lèi) IndexSearcher 的構(gòu)造函數(shù)接受一個(gè)類(lèi)型為 Directory 的對(duì)象, Directory 是一個(gè)抽象類(lèi),它目前有兩個(gè)子類(lèi): FSDirctory RAMDirectory. 我們的程序中傳入了一個(gè) FSDirctory 對(duì)象作為其參數(shù),代表了一個(gè)存儲(chǔ)在磁盤(pán)上的索引的位置。構(gòu)造函數(shù)執(zhí)行完成后,代表了這個(gè) IndexSearcher 以只讀的方式打開(kāi)了一個(gè)索引。然后我們程序構(gòu)造了一個(gè) Term 對(duì)象,通過(guò)這個(gè) Term 對(duì)象,我們指定了要在文檔的內(nèi)容中搜索包含關(guān)鍵詞 ”lucene” 的文檔。接著利用這個(gè) Term 對(duì)象構(gòu)造出 TermQuery 對(duì)象并把這個(gè) TermQuery 對(duì)象傳入到 IndexSearcher search 方法中進(jìn)行查詢(xún),返回的結(jié)果保存在 Hits 對(duì)象中。最后我們用了一個(gè)循環(huán)語(yǔ)句把搜索到的文檔的路徑都打印了出來(lái)。 好了,我們的搜索應(yīng)用程序已經(jīng)開(kāi)發(fā)完畢,怎么樣,利用 Lucene 開(kāi)發(fā)搜索應(yīng)用程序是不是很簡(jiǎn)單。

回頁(yè)首

總結(jié)

本文首先介紹了 Lucene 的一些基本概念,然后開(kāi)發(fā)了一個(gè)應(yīng)用程序演示了利用 Lucene 建立索引并在該索引上進(jìn)行搜索的過(guò)程。希望本文能夠?yàn)閷W(xué)習(xí) Lucene 的讀者提供幫助。

?

Lucence3.0學(xué)習(xí)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 中文字幕在线观看一区二区 | 99热成人精品热久久669 | 嘿咻成人免费视频欧美激情 | 中文字幕欧美亚洲 | 99精品国产综合久久久久 | 国产精品久久久久国产精品 | 久久久91 | 久久中文在线 | 国产精品久久久久久永久牛牛 | 中文字幕人成乱码第一页 | 亚洲欧美一区二区三区四区 | 国产精品亚洲一区二区在线观看 | 久久精品视频免费在线观看 | 亚洲国产天堂久久九九九 | 久青草免费在线视频 | 久久的爱久久的你 | h视频在线观看免费网站 | 久久人人爽人人爽人人片av不 | 久久天天躁夜夜躁狠狠躁2015 | 九九影院理论片 | 日韩不卡视频在线观看 | 亚洲第一伊人 | 欧美人在线一区二区三区 | 日日碰夜夜操 | 国产成人精品免费影视大全 | 日韩伦理一区二区三区 | www.日日干| 精品偷拍模特露出丝袜在线 | 亚洲综合网在线观看首页 | 色狠狠色综合吹潮 | 在线播放亚洲视频 | 天天舔夜夜操 | 成人网在线免费观看 | 一级黄片一级毛片 | 亚洲午夜久久影院 | 欧美在线色 | 亚洲欧洲免费 | 一区二区三区 日韩 | 日本在线小视频 | 视频精品一区二区三区 | 亚洲国产精品乱码一区二区三区 |