對使用Lucene的一點點認識

jopen 10年前發布 | 19K 次閱讀 Lucene 搜索引擎

就我而言我使用Lucene就是為了搜索而已,所以我就以這個目的來描述這個筆記。我使用Lucene的步驟如下:

1:創建索引

2:學習有哪些過濾器

3:學習有哪些查詢器(很多)

4:學習有哪些分詞器(很多,很重要)

1)創建索引

/**

 * @param  args

 * 這個是在文檔目錄中增加

這個例子是把docs目錄下的文件都添加所以到index文件里面

 */

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

String indexPath="C:\\Users\\Administrator\\Workspaces\\MyEclipse9\\Lucene01\\index";

String docsPath="C:\\Users\\Administrator\\Workspaces\\MyEclipse9\\Lucene01\\docs";

//這段代碼我們注意一下,因為我們創建所以的目錄有兩種方式,一種是真實的文件目錄,一種是內存目錄,一般內存目錄是為了我們方便測試用的,我們這兒用的是真實的目錄

Directory dir=FSDirectory.open(new File(indexPath));

Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_45);

IndexWriterConfig iwc=new IndexWriterConfig(Version.LUCENE_45,analyzer);

IndexWriter writer=new IndexWriter(dir,iwc);

File docDir=new File(docsPath);

indexDocs(writer,docDir);

writer.close();

dir.close();

}

public static void indexDocs(IndexWriter writer,File file) throws Exception{

if(file.canRead()){

if(file.isDirectory()){

String[] files=file.list();

if(files!=null){

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

System.out.println(files[i]+"2");

//根據 parent 抽象路徑名和 child 路徑名字符串創建一個新 File 實例。

//File(File parent, String child) 

indexDocs(writer,new File(file,files[i]));

}

}

}else{

FileInputStream fis ;

try {

fis = new FileInputStream(file);

catch (FileNotFoundException e) {

return;

}

Document doc = new Document();

Field PathField = new StringField("path",file.getPath(),Field.Store.YES);

doc.add(PathField);

doc.add(new LongField("modified",file.lastModified(),Field.Store.NO));

try {

doc.add(new TextField("contents",new BufferedReader(new InputStreamReader(fis,"UTF-8"))));

writer.addDocument(doc);

catch (UnsupportedEncodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

finally {

fis.close();

}

System.out.println("writer.addDocument(doc)-file.getPath():"+file.getPath());

System.out.println("writer.numDocs():"+writer.numDocs());

System.out.println("writer.maxDoc():"+writer.maxDoc());

System.out.println("writer.numRamDocs():"+writer.numRamDocs());

}

}

}

(2)過濾器

我感覺不是很重要,所以這兒就不提了。

(3)查詢器

很多,但是也好理解,我的有很多代碼的例子,所以這兒也不說了。

4)分詞器

我們的分詞器有很多,但是常用的就有一下幾種(針對的是西文的分詞器)

,我們可以到文檔之中去查找。

1:StandardAnalyzer支持漢語,混合分詞。

2:StopAnalyzer去掉一些連接詞,is,or啊之類的無意義的詞,還有空格之類的連接詞。

3:SimpleAnalyzer就是分割一些空格,連接符之類的。

如何使用呢?

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

Directory dir=new RAMDirectory();

//想用成什么樣的分詞器就寫什么樣的分詞器,包括寫成后面說的中文分詞器

Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_45);

IndexWriterConfig iwriter=new IndexWriterConfig(Version.LUCENE_45,analyzer);

IndexWriter writer=new IndexWriter(dir,iwriter);

Document doc=new Document();

Field f=new TextField("content","xy&z mail is - xyz@hello.com,中文",Store.YES);

doc.add(f);

writer.addDocument(doc);

writer.close();

DirectoryReader dr= DirectoryReader.open(dir);

IndexSearcher is=new IndexSearcher(dr);

    QueryParser parser=new QueryParser(Version.LUCENE_45,"content",analyzer);

Query query=parser.parse("\"xyz@hello.com,中文\"");

ScoreDoc[] hits=is.search(query, 100).scoreDocs;

System.out.println(query.toString());

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

Document document=is.doc(hits[i].doc);

System.out.println(hits[i]+"content:"+document.get("content"));

}

dr.close();

dr.close();

}

下面這段代碼是驗證上面提的這些分詞器是如何分詞的,打印分詞的效果。

public static void main(String[] argsthrows Exception {

//Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_45);

Analyzer analyzer=new SimpleAnalyzer(Version.LUCENE_45);

//獲取lucenetokenstream對象

TokenStream ts=analyzer.tokenStream("content"new StringReader("xy&z mail is - xyz@hello.com,中文"));

//獲取詞源位置屬性

OffsetAttribute offset=ts.addAttribute(OffsetAttribute.class);

CharTermAttribute term=ts.addAttribute(CharTermAttribute.class);

//獲取詞源文本屬性

TypeAttribute type=ts.addAttribute(TypeAttribute.class);

ts.reset();

while(ts.incrementToken()){

System.out.println(offset.startOffset()+"-"+offset.endOffset()+":"+term.toString());

}

ts.end();

ts.close();

}

打印結果:

0-2:xy|word

3-4:z|word

5-9:mail|word

10-12:is|word

15-18:xyz|word

19-24:hello|word

25-28:com|word

29-31:中文|word

重點介紹的是中文的分詞器:

IK Analyzer

它的安裝部署十分簡單,將IKAnalyzer2012.jar部署亍項目的lib目彔中;IKAnalyzer.cfg.xml和 stopword.dic文件放置在class根目彔(對亍web項目,通常是WEB-INF/classes目彔,同hibernate、log4j等配置文件相同)下即可。

使用方法跟上面是一模一樣的,具體效果是什么樣,可以自己測試,也可以看它的文檔。

綜合使用

思考1

我這兒創建索引的時候針對的都是txt文檔,要是還有其他的比如視頻格式,PDFXML等等之類的格式呢?

好辦,我們用tika這個包。使用代碼如下:

/**初始化給目錄下的所有文件都建索引

 * @param  args

 */

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

String indexPath=INDEX;

String docsPath=INDEX_PATH.replace(".","\\");

Directory dir=FSDirectory.open(new File(indexPath));

Analyzer analyzer=new IKAnalyzer(true);

IndexWriterConfig iwc=new IndexWriterConfig(Version.LUCENE_43,analyzer);

iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);

IndexWriter writer=new IndexWriter(dir,iwc);

File file=new File(docsPath);

indexDocs(writer,file);

writer.close();

dir.close();

}

public static void indexDocs(IndexWriter writer,File file) throws IOException {

if(file.canRead()){

if(file.isDirectory()){//如果是文件夾

String[] filelist=file.list();

if(filelist!=null){

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

indexDocs(writer,new File(file,filelist[i]));

}

}

}else{

//如果不是文件夾

FileInputStream fis;

try {

fis = new FileInputStream(file);

catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

return ;

}

Document doc=new Document();

Field PathField = new StringField(PATH_FIELD_NAME,file.getPath(),Field.Store.YES); 

doc.add(PathField);

doc.add(new LongField(MODIFIED_FIELD_NAME,file.lastModified(),Field.Store.NO));

//我們用tika來解析我們的流

try{

ContentHandler handler = new BodyContentHandler();

Parser parser = new AutoDetectParser();

Metadata meta = new Metadata();

parser.parse(fis, handler, meta, new ParseContext());

doc.add(new TextField(CONTENTS_FIELD_NAME,""+file.getName()+""+handler.toString(),Field.Store.YES));

writer.updateDocument(new Term(PATH_FIELD_NAME, file.getPath()),doc);

writer.commit();

}catch (Exception e){

e.printStackTrace();

}finally{

fis.close();

}

System.out.println("%%%%%%%%%%%%%%%%%%%%");

System.out.println("writer.updateDocument(doc)-file.getPath():"+file.getPath());

System.out.println("writer.numDocs():"+writer.numDocs());

System.out.println("writer.maxDoc():"+writer.maxDoc());

System.out.println("writer.numRamDocs():"+writer.numRamDocs());

}

}

}

 

}

 

Tika相當于是一個萬能的解析工具了。

 

思考2

百度文庫人家查出來你要搜索的詞包含在文中,文中使用高亮顯示的啊,我能嗎?

能!

代碼如下:

public void Searcher(String danci,Integer pageno,Integer pagesize)throws Exception{

String indexPath = INDEX;

Directory dir = FSDirectory.open(new File(indexPath));

Analyzer analyzer = new IKAnalyzer(true);

DirectoryReader ireader = DirectoryReader.open(dir);

IndexSearcher searcher = new IndexSearcher(ireader);

QueryParser parser = new QueryParser(Version.LUCENE_43,CONTENTS_FIELD_NAME,analyzer); 

Query query = parser.parse(danci);

System.out.println("QueryParser:"+query.toString());

if(pageno*pagesize>querysize){

querysize=pageno*pagesize;

}

ScoreDoc[] hits = searcher.search(query, querysize).scoreDocs;

//高亮設置

SimpleHTMLFormatter simpleHtmlFormatter = new SimpleHTMLFormatter("<font color=red>","</font>");

Highlighter highlighter = new Highlighter(simpleHtmlFormatter,new QueryScorer(query));

highlighter.setTextFragmenter(new SimpleFragmenter(150));

Integer start=(pageno-1)*pagesize;

Integer end=pageno*pagesize;

hitslength=hits.length;

if(hits.length>start){

if(pagesize*pageno>hits.length) end=hits.length;

for (Integer i=start;i<end;i++){

fileatr=new FileAtr();

Document doc = searcher.doc(hits[i].doc);

String strpath = doc.get(PATH_FIELD_NAME);

fileatr.setLujing(strpath);//添加文件的路徑

fileatr.setFileName(getFileNameByPath(strpath));

//這兒也是為了高亮顯示

TokenStream tokenStream = analyzer.tokenStream(CONTENTS_FIELD_NAMEnew StringReader(doc.get(CONTENTS_FIELD_NAME)));

String str = highlighter.getBestFragment(tokenStream, doc.get(CONTENTS_FIELD_NAME));

fileatr.setContents(str);

filelist.add(fileatr);

}

}

System.out.println(hits.length+"這是多少");

pagecount=hits.length/pagesize;

if( pageno >= pagecountpagecount = pageno;

//  System.out.prIntegerln("ireader.numDeletedDocs()"+ireader.numDeletedDocs());

//  System.out.prIntegerln("ireader.numDocs()"+ireader.numDocs());

//  System.out.prIntegerln("ireader.maxDoc()"+ireader.maxDoc());

ireader.close();

dir.close();

}

 

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!