`

lucene3.0学习笔记2-(再学Lucene的简单例子)

阅读更多
又在看Lucene,这回Lucene变成3.0了,太快了,Lucene in action 第二版也出来了
所以决定看一看

做了两个简单的例子
创建索引
package com.langhua;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
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.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
/**
 * 创建索引 Lucene 3.0+
 * @author Administrator
 *
 */
public class Indexer {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//保存索引文件的地方
		String indexDir = "F:\\indexDir";
		//将要搜索TXT文件的地方
		String dateDir = "F:\\dateDir";
		IndexWriter indexWriter = null;
		//创建Directory对象
		Directory dir = new SimpleFSDirectory(new File(indexDir));
		//创建IndexWriter对象,第一个参数是Directory,第二个是分词器,第三个表示是否是创建,如果为false为在此基础上面修改,第四表示表示分词的最大值,比如说new MaxFieldLength(2),就表示两个字一分,一般用IndexWriter.MaxFieldLength.LIMITED 
		indexWriter = new IndexWriter(dir,new StandardAnalyzer(Version.LUCENE_30),true,IndexWriter.MaxFieldLength.UNLIMITED);
		File[] files = new File(dateDir).listFiles();
		for (int i = 0; i < files.length; i++) {
			Document doc = new Document();
			//创建Field对象,并放入doc对象中
			doc.add(new Field("contents", new FileReader(files[i]))); 
			doc.add(new Field("filename", files[i].getName(), 
								Field.Store.YES, Field.Index.NOT_ANALYZED));
			doc.add(new Field("indexDate",DateTools.dateToString(new Date(), DateTools.Resolution.DAY),Field.Store.YES,Field.Index.NOT_ANALYZED));
			//写入IndexWriter
			indexWriter.addDocument(doc);
		}
		//查看IndexWriter里面有多少个索引
		System.out.println("numDocs"+indexWriter.numDocs());
		indexWriter.close();
		
	}

}



搜索索引 Lucene 3.0+

package com.langhua;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.ParseException;
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.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
/**
 * 搜索索引 Lucene 3.0+
 * @author Administrator
 *
 */
public class Searcher {

	public static void main(String[] args) throws IOException, ParseException {
		//保存索引文件的地方
		String indexDir = "F:\\indexDir";
		Directory dir = new SimpleFSDirectory(new File(indexDir));
		//创建 IndexSearcher对象,相比IndexWriter对象,这个参数就要提供一个索引的目录就行了
		IndexSearcher indexSearch = new IndexSearcher(dir);
		//创建QueryParser对象,第一个参数表示Lucene的版本,第二个表示搜索Field的字段,第三个表示搜索使用分词器
		QueryParser queryParser = new QueryParser(Version.LUCENE_30,
				"contents", new StandardAnalyzer(Version.LUCENE_30));
		//生成Query对象
		Query query = queryParser.parse("langhua9527");
		//搜索结果 TopDocs里面有scoreDocs[]数组,里面保存着索引值
		TopDocs hits = indexSearch.search(query, 10);
		//hits.totalHits表示一共搜到多少个
		System.out.println("找到了"+hits.totalHits+"个");
		//循环hits.scoreDocs数据,并使用indexSearch.doc方法把Document还原,再拿出对应的字段的值
		for (int i = 0; i < hits.scoreDocs.length; i++) {
			ScoreDoc sdoc = hits.scoreDocs[i];
			Document doc = indexSearch.doc(sdoc.doc);
			System.out.println(doc.get("filename"));			
		}		
		indexSearch.close();
	}
}

分享到:
评论
22 楼 baby8117628 2010-12-18  

纠结的码农..........路过
21 楼 lyj552041 2010-09-02  
不错,我根据楼主的代码写了一个成功的例子。
20 楼 chudu 2010-07-15  
chudu 写道
楼主,我根据你的代码,运行后英文可以正确检索出,但中文不行,将分词换成IKAnalyzer也只能检索英文,不能检索中文,原因出在哪儿哦?

贴代码,求解决:
package org.lucene.mytest;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
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.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class IndexTest {

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		// 保存索引文件的地方
		String indexDir = "D:\\study\\lucene\\index";
		// 将要搜索TXT文件的地方
		String dateDir = "D:\\study\\lucene\\data";
		IndexWriter indexWriter = null;
		// 创建Directory对象
		Directory dir = new SimpleFSDirectory(new File(indexDir));
		// 创建IndexWriter对象,第一个参数是Directory,第二个是分词器,第三个表示是否是创建,如果为false为在此基础上面修改,第四表示表示分词的最大值,比如说new
		// MaxFieldLength(2),就表示两个字一分,一般用 IndexWriter.MaxFieldLength.LIMITED
		indexWriter = new IndexWriter(dir, new IKAnalyzer(), true,
				IndexWriter.MaxFieldLength.UNLIMITED);
		File[] files = new File(dateDir).listFiles();
		for (int i = 0; i < files.length; i++) {
			Document doc = new Document();
			// 创建Field对象,并放入doc对象中
			doc.add(new Field("contents", new FileReader(files[i])));
			doc.add(new Field("filename", files[i].getName(), Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			doc.add(new Field("indexDate", DateTools.dateToString(new Date(),
					DateTools.Resolution.DAY), Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			// 写入IndexWriter
			indexWriter.addDocument(doc);
		}
		// 查看IndexWriter里面有多少个索引
		System.out.println("numDocs" + indexWriter.numDocs());
		indexWriter.close();

	}

}


package org.lucene.mytest;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.ParseException;
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.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class SearchTest {
	public static void main(String[] args) throws IOException, ParseException {
		// 保存索引文件的地方
		String indexDir = "D:\\study\\lucene\\index";
		Directory dir = new SimpleFSDirectory(new File(indexDir));
		// 创建 IndexSearcher对象,相比IndexWriter对象,这个参数就要提供一个索引的目录就行了
		IndexSearcher indexSearch = new IndexSearcher(dir);
		// 创建QueryParser对象,第一个参数表示Lucene的版本,第二个表示搜索Field的字段,第三个表示搜索使用分词器
		QueryParser queryParser = new QueryParser(Version.LUCENE_30,
				"contents", new IKAnalyzer());
		// 生成Query对象
		Query query = queryParser.parse("重要的生活星球");
		// Query query=new TermQuery(new Term("contents","重要的生活星球"));
		// 搜索结果 TopDocs里面有scoreDocs[]数组,里面保存着索引值
		TopDocs hits = indexSearch.search(query, 10);
		// hits.totalHits表示一共搜到多少个
		System.out.println("找到了" + hits.totalHits + "个");
		// 循环hits.scoreDocs数据,并使用indexSearch.doc方法把Document还原,再拿出对应的字段的值
		for (int i = 0; i < hits.scoreDocs.length; i++) {
			ScoreDoc sdoc = hits.scoreDocs[i];
			Document doc = indexSearch.doc(sdoc.doc);
			System.out.println(doc.get("filename"));
		}
		indexSearch.close();
	}
}

19 楼 chudu 2010-07-15  
楼主,我根据你的代码,运行后英文可以正确检索出,但中文不行,将分词换成IKAnalyzer也只能检索英文,不能检索中文,原因出在哪儿哦?
18 楼 77tt77 2010-06-28  
多谢楼主的入门例子,和1978关于lucene的一系列文章。

都是好人。
17 楼 lili.cn 2010-04-26  
如果用了 Field.Index.NOT_ANALYZED的话就不能用QueryParser 了,QueryParser 只查分词索引,所以查询因该写成
Query query = new TermQuery(new Term("filename", name1));
TopDocs hits = indexSearch.search(query, 20);
       
16 楼 MultiArrow 2010-02-25  
对于以下代码:
//writer.commit();   
IndexSearcher searcher = new IndexSearcher(writer.getReader());

感觉用处不大,因为如果writer和searcher在同一个类的话还好,如果不在同一个类,searcher中调用writer应该会导致很多问题。
15 楼 MultiArrow 2010-02-25  
问题解决了,谢谢楼上两位,俺就是看你们的文章入门的。
14 楼 langhua9527 2010-02-24  
谢谢,非常感谢。。。。明天上班看你的文章哈。。。。
13 楼 forfuture1978 2010-02-24  
上述问题,仅从表象上来说应该是在添加完Document后,IndexWriter没有commit或者close,致使添加的文档不能够被打开的IndexReader或IndexSearcher看到,所以不能够搜索出来。

我做了以下程序,也是当IndexWriter.commit调用则搜的出来,否则搜不出来,代码如下:

    String driver = "org.apache.derby.jdbc.EmbeddedDriver";
    String url = "jdbc:derby:";
    Class.forName(driver).newInstance();
    Connection connection = DriverManager.getConnection(url+"TestIndexDatabaseField/Database;create=true");
    Statement createstmt = connection.createStatement();
    String dbcreatesql = "CREATE TABLE TestIndexDatabaseField (name VARCHAR(50) PRIMARY KEY)";
    createstmt.executeUpdate(dbcreatesql);
    createstmt.close();

    String insertsql = "INSERT INTO TestIndexDatabaseField (name) " + "VALUES(?)";
    PreparedStatement stmt = connection.prepareStatement(insertsql);
    stmt.setString(1, "properties");
    stmt.executeUpdate();
    stmt.close();

    String selectsql = "SELECT name FROM TestIndexDatabaseField";
    stmt = connection.prepareStatement(selectsql);
    ResultSet rs = stmt.executeQuery();
    File indexDir = new File("TestIndexDatabaseField/Index");
    IndexWriter writer = new IndexWriter(FSDirectory.open(indexDir), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED);

    while (rs.next()) {
      String name = rs.getString("name");
      Document doc = new Document();
      doc.add(new Field("name", name, Field.Store.YES, Field.Index.NOT_ANALYZED));
      writer.addDocument(doc);
    }

    rs.close();
    stmt.close();
    //commit is here
    writer.commit();
    
    IndexSearcher searcher = new IndexSearcher(FSDirectory.open(indexDir));
    QueryParser parser = new QueryParser(Version.LUCENE_30, "name", new StandardAnalyzer(Version.LUCENE_30));
    Query query = parser.parse("properties");
    TopDocs docs = searcher.search(query, 10);
    for (ScoreDoc doc : docs.scoreDocs) {
      System.out.println("docid : " + doc.doc + " score : " + doc.score);
      Document ldoc = searcher.doc(doc.doc);
      System.out.println(ldoc.get("name"));
    }
    searcher.close();
    
    writer.close();


这是Lucene对类似数据库的事务的支持:
1.IndexWriter添加文档后,如果不commit,则不能被新打开的IndexReader看到从上次commit至今的文档。
2.IndexReader一旦打开,相当于对当前的索引建立了一个snapshot,仅能看到此时间之前commit过的文档,除非此IndexReader重新打开,否则即便IndexWriter添加了文档,并且commit了,也不能够被搜到。
3.为了支持实时索引搜索,Lucene 3.0提供了IndexWriter.getReader方法,使得不commit的文档也能够被看到。
在上述代码中注释掉writer.commit()函数,然而创建IndexSearcher的时候应用以下代码,则也能够搜的出来。
    //writer.commit();
    IndexSearcher searcher = new IndexSearcher(writer.getReader());


不知道是否回答了您的问题,欢迎讨论
12 楼 MultiArrow 2010-02-24  
照做了,依然找不到结果。
补充一下:我的表里只有一个name字段,搜索的"properties"是字段的一个值。
11 楼 MultiArrow 2010-02-24  
langhua9527 写道

//System.out.println(rs.getString("name")); 

注了
或者
System.out.println(rs.getString("name")); 
System.out.println(rs.getString("name")); 

输出两次,看一下第二次取出来的值是多少

或者
doc.add(new Field("name", ((String)rs.getString("name")).trim(),   
Field.Store.YES, Field.Index.NOT_ANALYZED)); 

照做了,依然找不到结果。
补充一下:我的表里只有一个name字段,搜索的"properties"是字段的一个值。
10 楼 langhua9527 2010-02-24  

//System.out.println(rs.getString("name")); 

注了
或者
System.out.println(rs.getString("name")); 
System.out.println(rs.getString("name")); 

输出两次,看一下第二次取出来的值是多少

或者
doc.add(new Field("name", ((String)rs.getString("name")).trim(),   
Field.Store.YES, Field.Index.NOT_ANALYZED)); 
9 楼 MultiArrow 2010-02-24  
这是搜索的代码(searcher):
String indexDir= "D:\\workspace\\luceneworkspace\\jspluceneIndex";
		Directory dir = new SimpleFSDirectory(new File(indexDir));
		IndexSearcher indexSearch = new IndexSearcher(dir);
		QueryParser queryParser = new QueryParser(Version.LUCENE_30, "name",
				new StandardAnalyzer(Version.LUCENE_30));
		Query query = queryParser.parse("properties");
		TopDocs hits = indexSearch.search(query, 20);
		System.out.println("一共找到" + hits.totalHits + "条");
		for (int i = 0; i < hits.scoreDocs.length; i++) {
			ScoreDoc sdoc = hits.scoreDocs[i];
			Document doc = indexSearch.doc(sdoc.doc);
			System.out.println(doc.get("name"));
		}
		indexSearch.close();

properties是表中有的,不过还是找不到结果。这个代码有什么问题吗?
8 楼 langhua9527 2010-02-24  
// 连接数据库 
Connection conn = db.getConnection(); 
PreparedStatement stmt = conn.prepareStatement(sql); 
ResultSet rs = stmt.executeQuery(); 

// 为表字段建立索引 
Directory dir = new SimpleFSDirectory(new File(indexDir)); 
IndexWriter indexWriter = new IndexWriter(dir, 
new StandardAnalyzer(Version.LUCENE_30), true, 
IndexWriter.MaxFieldLength.UNLIMITED); 
while (rs.next()) { 
System.out.println(rs.getString("name")); 
Document doc = new Document(); 
doc.add(new Field("name", rs.getString("name"), 
Field.Store.YES, Field.Index.NOT_ANALYZED)); 
indexWriter.addDocument(doc); 
} 

你这样建立也应该是找的出来的哈
Field.Index.NOT_ANALYZED这个表示不分词,但是要建立索引。。所以搜索的时候必须搜
rs.getString("name")这个才搜的出来
你再试一下
doc.add(new Field("name", (String)rs.getString("name"),
Field.Store.YES, Field.Index.NOT_ANALYZED));
7 楼 MultiArrow 2010-02-24  
晕了,5楼的排版怎么变成了这样 ,重来:

// 连接数据库
Connection conn = db.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();

// 为表字段建立索引
Directory dir = new SimpleFSDirectory(new File(indexDir));
IndexWriter indexWriter = new IndexWriter(dir,
new StandardAnalyzer(Version.LUCENE_30), true,
IndexWriter.MaxFieldLength.UNLIMITED);
while (rs.next()) {
System.out.println(rs.getString("name"));
Document doc = new Document();
doc.add(new Field("name", rs.getString("name"),
Field.Store.YES, Field.Index.NOT_ANALYZED));
indexWriter.addDocument(doc);
}


刚学lucene,问题比较多,请楼主有时间帮一下忙,thx!
6 楼 MultiArrow 2010-02-24  
还有,我为数据库的一个字段建立索引,不使用分词。将程序修改如下:
// 连接数据库
Connection conn = db.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();

// 为表字段建立索引
Directory dir = new SimpleFSDirectory(new File(indexDir));
IndexWriter indexWriter = new IndexWriter(dir,
new StandardAnalyzer(Version.LUCENE_30), true,
IndexWriter.MaxFieldLength.UNLIMITED);
while (rs.next()) {
System.out.println(rs.getString("name"));
Document doc = new Document();
[color=blue][/color]
indexWriter.addDocument(doc);
}
但是搜索不出结果,不知道是不是还是Field字段的问题?
5 楼 MultiArrow 2010-02-24  
晕,颜色标错了,应该是这一句:
Field.Index.ANALYZED_NO_NORMS:使用分词索引,不使用存储规则。

楼主将就着看一下
4 楼 MultiArrow 2010-02-24  
换成了Field.Index.ANALYZED_NO_NORMS,程序没问题了。上网查了一下:

Field.Index有五个属性,分别是:

Field.Index.ANALYZED:分词索引

Field.Index.NOT_ANALYZED:分词进行索引,如作者名,日期等,Rod Johnson本身为一单词,不再需要分词。

Field.Index.NO:不进行索引,存放不能被搜索的内容如文档的一些附加属性如文档类型, URL等。

Field.Index.NOT_ANALYZED_NO_NORMS:不使用分词索引,不使用存储规则。

Field.Index.ANALYZED_NO_NORMS:使用分词索引,不使用存储规则。

楼主能不能解释一下?
3 楼 langhua9527 2010-02-23  
MultiArrow 写道
3Q,例子很有用!不过我想根据文件名来索引,所以修改了一下程序,即把Searcher的:
QueryParser queryParser = new QueryParser(Version.LUCENE_30,  
                "contents", new StandardAnalyzer(Version.LUCENE_30));
修改如下:
QueryParser queryParser = new QueryParser(Version.LUCENE_30,  
                "filename", new StandardAnalyzer(Version.LUCENE_30));
即让contents换成filename。
但是却搜索不出结果,是不是这样修改还不行?

这样修改是可以的,但是原因是你在建立索引的时候参数不对
doc.add(new Field("filename",fileList[i].getName(),Field.Store.YES,Field.Index.ANALYZED_NO_NORMS));

Field.Index.有多个值哈。。。

相关推荐

Global site tag (gtag.js) - Google Analytics