- 浏览: 188526 次
- 性别:
- 来自: 杭州
最新评论
-
wahahachuang5:
web实时推送技术使用越来越广泛,但是自己开发又太麻烦了,我觉 ...
转发:websocket 通信协议介绍 -
爱很执着:
好
Java多线程同步机制(synchronized) -
我在路上看风景:
不错啊,看完了,疑惑不存在了。 新浪微博@最美最好的你
Java多线程同步机制(synchronized) -
hbiao68:
写得很好,受教了
Java Resource路径总结二 -
JamesLiuX:
有Freelancer的老鸟吗,求组队!
Freelancer
最近项目要用到Lucene,网上搜索了一些基础作为学习记录。
1 、整体结构说明
索引和搜索过程图:
API 使用示例图:
1. 索引过程:
1) 有一系列被索引文件
2) 被索引文件经过语法分析和语言处理形成一系列词 (Term) 。
3) 经过索引创建形成词典和反向索引表。
4) 通过索引存储将索引写入硬盘。
2. 搜索过程:
a) 用户输入查询语句。
b) 对查询语句经过语法分析和语言分析得到一系列词 (Term) 。
c) 通过语法分析得到一个查询树。
d) 通过索引存储将索引读入到内存。
e) 利用查询树搜索索引,从而得到每个词 (Term) 的 文档链表,对文档链表进行交,差,并得到结果文档。
f) 将搜索到的结果文档对查询的相关性进行排序。
g) 返回查询结果给用户。
2 、基本使用说明
lucene 索引的单元对象是 Document, 它可以是一个文本、一封 email 或者一个网页等,其中 Document 包含多个 Field ,一个 Field 就是它的一个属性,比如“文件路径”、“作者”,“文件内容”等都是 Field
1 )索引用类:
Java代码
1. /**
2. * 对目录进行Lucene索引
3. * @author roy
4. *
5. */
6. public class Indexer {
7. private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引结果存放目录
8. private static String DATA_DIR = "G:\\ROY的各种笔记"; //被索引文件存放的目录
9.
10. /**
11. * 测试主函数
12. * @param args
13. * @throws Exception
14. */
15. public static void main(String[] args) throws Exception{
16. long start = new Date().getTime();
17. int numIndexed = index(new File(INDEX_DIR),new File(DATA_DIR));//调用index方法
18. long end = new Date().getTime();
19. System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
20. }
21.
22. /**
23. * 索引dataDir下的.txt文件,并储存在indexDir下,返回索引的文件数量
24. * @param indexDir
25. * @param dataDir
26. * @return
27. * @throws IOException
28. */
29. private static int index(File indexDir, File dataDir) throws Exception{
30. if(!dataDir.exists() || !dataDir.isDirectory()){
31. throw new Exception("被索引的文件不存在!");
32. }
33. if(!indexDir.exists() || !indexDir.isDirectory()){
34. indexDir.mkdirs();
35. }
36. IndexWriter writer = new IndexWriter(
37. FSDirectory.open(indexDir),
38. new StandardAnalyzer(Version.LUCENE_30),
39. true,
40. IndexWriter.MaxFieldLength.UNLIMITED
41. );
42. //按照目录进行递归索引
43. indexDirectory(writer,dataDir);
44. int numIndexed = writer.numDocs();
45. //对索引后的结果加以优化
46. writer.optimize();
47. writer.close();
48. return numIndexed;
49. }
50. /**
51. * 循环遍历目录下的所有.doc文件并进行索引
52. * @param writer
53. * @param dir
54. * @throws IOException
55. */
56. private static void indexDirectory(IndexWriter writer, File dir) throws IOException {
57. File[] files = dir.listFiles();
58. for (int i = 0; i < files.length; i++) {
59. File f = files[i];
60. if (f.isDirectory()) {
61. indexDirectory(writer, f); // recurse
62. } else if (f.getName().endsWith(".doc")) {
63. indexFile(writer, f);
64. }
65. }
66. }
67. /**
68. * 对单个doc文件进行索引
69. * @param writer
70. * @param f
71. * @throws IOException
72. */
73. private static void indexFile(IndexWriter writer, File f)
74. throws IOException {
75. if (f.isHidden() || !f.exists() || !f.canRead()) {
76. return;
77. }
78. System.out.println("Indexing " + f.getCanonicalPath());
79. Document doc = new Document();
80. doc.add(new Field("content",new FileReader(f)));
81. doc.add(new Field("filename",f.getName(),Field.Store.YES, Field.Index.ANALYZED));
82. doc.add(new Field("path",f.getCanonicalPath(),Field.Store.YES, Field.Index.ANALYZED));
83. writer.addDocument(doc);
84. }
85. }
/**
* 对目录进行Lucene索引
* @author roy
*
*/
public class Indexer {
private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引结果存放目录
private static String DATA_DIR = "G:\\ROY的各种笔记"; //被索引文件存放的目录
/**
* 测试主函数
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
long start = new Date().getTime();
int numIndexed = index(new File(INDEX_DIR),new File(DATA_DIR));//调用index方法
long end = new Date().getTime();
System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
}
/**
* 索引dataDir下的.txt文件,并储存在indexDir下,返回索引的文件数量
* @param indexDir
* @param dataDir
* @return
* @throws IOException
*/
private static int index(File indexDir, File dataDir) throws Exception{
if(!dataDir.exists() || !dataDir.isDirectory()){
throw new Exception("被索引的文件不存在!");
}
if(!indexDir.exists() || !indexDir.isDirectory()){
indexDir.mkdirs();
}
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexDir),
new StandardAnalyzer(Version.LUCENE_30),
true,
IndexWriter.MaxFieldLength.UNLIMITED
);
//按照目录进行递归索引
indexDirectory(writer,dataDir);
int numIndexed = writer.numDocs();
//对索引后的结果加以优化
writer.optimize();
writer.close();
return numIndexed;
}
/**
* 循环遍历目录下的所有.doc文件并进行索引
* @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(".doc")) {
indexFile(writer, f);
}
}
}
/**
* 对单个doc文件进行索引
* @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("content",new FileReader(f)));
doc.add(new Field("filename",f.getName(),Field.Store.YES, Field.Index.ANALYZED));
doc.add(new Field("path",f.getCanonicalPath(),Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
}
}
2 )查询用类:
Java代码
1. /**
2. * 对索引结果进行搜索
3. * @author roy
4. *
5. */
6. public class Searcher {
7. private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引所在的路径
8. private static String KEYWORD = "自己"; //关键词
9. private static int TOP_NUM = 100; //显示前100条结果
10. /**
11. * 测试主函数
12. * @param args
13. * @throws Exception
14. */
15. public static void main(String[] args) throws Exception{
16. File indexDir = new File(INDEX_DIR);
17. if (!indexDir.exists() || !indexDir.isDirectory()){
18. throw new Exception(indexDir + "索引目录不存在!");
19. }
20. search(indexDir,KEYWORD); //调用search方法进行查询
21. }
22. /**
23. * 索引查找方法
24. * @param indexDir 索引所在的目录
25. * @param q 查询的字符串
26. * @throws Exception
27. */
28. private static void search(File indexDir, String q) throws Exception {
29. IndexSearcher is = new IndexSearcher(FSDirectory.open(indexDir),true); //read-only
30. String field = "content";
31. //创建查询解析器
32. QueryParser parser = new QueryParser(Version.LUCENE_30, field, new StandardAnalyzer(Version.LUCENE_30));
33. Query query = parser.parse(q);
34. //创建结果收集器
35. TopScoreDocCollector collector = TopScoreDocCollector.create(TOP_NUM ,false);//有变化的地方
36.
37. long start = new Date().getTime();// start time
38. is.search(query, collector);
39. ScoreDoc[] hits = collector.topDocs().scoreDocs;
40.
41. System.out.println(hits.length);
42. for (int i = 0; i < hits.length; i++) {
43. Document doc = is.doc(hits[i].doc);//new method is.doc()
44. System.out.println(doc.getField("filename")+" "+hits[i].toString()+" ");
45. }
46. long end = new Date().getTime();//end time
47.
48. System.out.println("Found " + collector.getTotalHits() +
49. " document(s) (in " + (end - start) +
50. " milliseconds) that matched query '" +
51. q + "':");
52. }
53. }
/**
* 对索引结果进行搜索
* @author roy
*
*/
public class Searcher {
private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引所在的路径
private static String KEYWORD = "自己"; //关键词
private static int TOP_NUM = 100; //显示前100条结果
/**
* 测试主函数
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
File indexDir = new File(INDEX_DIR);
if (!indexDir.exists() || !indexDir.isDirectory()){
throw new Exception(indexDir + "索引目录不存在!");
}
search(indexDir,KEYWORD); //调用search方法进行查询
}
/**
* 索引查找方法
* @param indexDir 索引所在的目录
* @param q 查询的字符串
* @throws Exception
*/
private static void search(File indexDir, String q) throws Exception {
IndexSearcher is = new IndexSearcher(FSDirectory.open(indexDir),true); //read-only
String field = "content";
//创建查询解析器
QueryParser parser = new QueryParser(Version.LUCENE_30, field, new StandardAnalyzer(Version.LUCENE_30));
Query query = parser.parse(q);
//创建结果收集器
TopScoreDocCollector collector = TopScoreDocCollector.create(TOP_NUM ,false);//有变化的地方
long start = new Date().getTime();// start time
is.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
System.out.println(hits.length);
for (int i = 0; i < hits.length; i++) {
Document doc = is.doc(hits[i].doc);//new method is.doc()
System.out.println(doc.getField("filename")+" "+hits[i].toString()+" ");
}
long end = new Date().getTime();//end time
System.out.println("Found " + collector.getTotalHits() +
" document(s) (in " + (end - start) +
" milliseconds) that matched query '" +
q + "':");
}
}
3 )选择分词器:
分词器是一个搜索引擎的核心之一,好的分词器可以把关键字分解为更接近于用户的搜索目标的词汇。
下面的方法可以显示分词器的分词结果:
Java代码
1. /**
2. * 查看分词后的结果
3. * @param analyzer 分词器
4. * @param s 需要分词的字符串
5. * @throws Exception
6. */
7. public static void showAnalyzerResult(Analyzer analyzer, String s) throws Exception {
8. StringReader reader = new StringReader(s);
9. TokenStream tokenStream = analyzer.tokenStream(s,reader);
10. tokenStream.addAttribute(TermAttribute.class);
11.
12. while (tokenStream.incrementToken()) {
13. TermAttribute ta = tokenStream.getAttribute(TermAttribute.class);
14. System.out.println(ta.term());
15. }
16. System.out.println();
17. }
/**
* 查看分词后的结果
* @param analyzer 分词器
* @param s 需要分词的字符串
* @throws Exception
*/
public static void showAnalyzerResult(Analyzer analyzer, String s) throws Exception {
StringReader reader = new StringReader(s);
TokenStream tokenStream = analyzer.tokenStream(s,reader);
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute ta = tokenStream.getAttribute(TermAttribute.class);
System.out.println(ta.term());
}
System.out.println();
}
4 )索引doc,pdf等文件:
默认情况下 lucene 会索引 lucene 文件,其他文件直接索引会出现大量错误。所以我们需要对 doc,pdf 这些文件进行预处理,先生成 txt 文件才可。
1、doc文件:
先下载最新的POI组件,使用其中的poi-3.6-20091214.jar和poi- scratchpad-3.6-20091214即可实现读取word文件中的纯文本内容
Java代码
1. InputStream is = new FileInputStream(f);
2. WordExtractor wordExtractor = new WordExtractor(is);
3. return wordExtractor.getText();
InputStream is = new FileInputStream(f);
WordExtractor wordExtractor = new WordExtractor(is);
return wordExtractor.getText();
2、pdf文件:
下载最新的pdf-box,把fontbox-1.1.0.jar、jempbox-1.1.0.jar、pdfbox-1.1.0.jar三个包放进项目路径中
Java代码
1. InputStream is = new FileInputStream(f);
2. PDFTextStripper ts = new PDFTextStripper();
3. PDDocument pDocument = PDDocument.load(is);
4. StringWriter writer = new StringWriter();
5. ts.writeText(pDocument,writer);
6. is.close();
7. pDocument.close();
8. return writer.getBuffer().toString();
InputStream is = new FileInputStream(f);
PDFTextStripper ts = new PDFTextStripper();
PDDocument pDocument = PDDocument.load(is);
StringWriter writer = new StringWriter();
ts.writeText(pDocument,writer);
is.close();
pDocument.close();
return writer.getBuffer().toString();
5、查看当前索引库的内容
下载最新Luke工具,解压到lucene文件夹下,在命令行输入:
java -classpath lukeall-0.7.1.jar;lucene-2.0.jar org.getopt.luke.Luke
即可
5 )索引的添加、删除和更新:
1、添加新的索引记录
Java代码
1. IndexWriter writer = new IndexWriter(
2. FSDirectory.open(indexFile),
3. analyzer,
4. false,
5. IndexWriter.MaxFieldLength.UNLIMITED
6. );
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexFile),
analyzer,
false,
IndexWriter.MaxFieldLength.UNLIMITED
);
在创建索引器的时候指定create参数为true表示新建立索引,false表示使用当前目录下已有的索引。此时为writer添加 document并optimize()即可
2、删除索引
Java代码
1. /**
2. * 暂时删除某个索引
3. * @param f
4. * @throws Exception
5. */
6. public static void deleteIndexTmp(File indexFile,String targetPath) throws Exception{
7. IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
8. ir.deleteDocuments(new Term("path",targetPath));
9. ir.close();
10. }
11. /**
12. * 恢复某个临时删除的索引
13. * @param f
14. * @throws Exception
15. */
16. public static void rollbackDelete(File indexFile) throws Exception{
17. IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
18. ir.undeleteAll();
19. ir.close();
20. }
21. /**
22. * 将标记为删除的索引真正删除
23. * @param f
24. * @throws Exception
25. */
26. public static void optimizeIndex(File indexFile) throws Exception{
27. IndexWriter writer = new IndexWriter(
28. FSDirectory.open(indexFile),
29. analyzer,
30. false,
31. IndexWriter.MaxFieldLength.UNLIMITED
32. );
33. writer.optimize();
34. writer.close();
35. }
/**
* 暂时删除某个索引
* @param f
* @throws Exception
*/
public static void deleteIndexTmp(File indexFile,String targetPath) throws Exception{
IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
ir.deleteDocuments(new Term("path",targetPath));
ir.close();
}
/**
* 恢复某个临时删除的索引
* @param f
* @throws Exception
*/
public static void rollbackDelete(File indexFile) throws Exception{
IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
ir.undeleteAll();
ir.close();
}
/**
* 将标记为删除的索引真正删除
* @param f
* @throws Exception
*/
public static void optimizeIndex(File indexFile) throws Exception{
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexFile),
analyzer,
false,
IndexWriter.MaxFieldLength.UNLIMITED
);
writer.optimize();
writer.close();
}
3、更新索引:
可以先查到旧索引将其删除,然后再新建索引即可。
Lucene3.0以后提供了新的update(Term,Document)方法,封装了上述两个操作。
6 )高级查询:
Java代码
1. /** *** 一个关键字,对一个字段进行查询 **** */
2. QueryParser qp = new QueryParser("content",analyzer);
3. query = qp.parse(keyword);
4. Hits hits = searcher.search(query);
5.
6. /** *** 模糊查询 **** */
7. Term term = new Term("content",keyword);
8. FuzzyQuery fq = new FuzzyQuery(term);
9. Hits hits = searcher.search(fq);
10.
11. /** *** 一个关键字,在两个字段中查询 **** */
12. /*
13. * 1.BooleanClause.Occur[] 的三种 类型: MUST : + and MUST_NOT : - not SHOULD : or
14. * 2.下面查询的意思是:content中 必须包含该关键字,而title有 没有都无所谓
15. * 3.下面的这个查询中,Occur[]的 长度必须和Fields[]的 长度一致。每个限制条件对应一个字段
16. */
17. BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};
18. query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer);
19.
20.
21. /** *** 两个(多个)关键 字对两个(多 个)字 段进行查询,默 认匹配规则 **** */
22. /*
23. * 1. 关键字的个数必须和字段的个数相等
24. * 2. 由于没有指定匹配规定,默认为"SHOULD" 因 此,下面查询的意思是:"title"中 含有keyword1 或 "content"含有 keyword2.
25. * 在此例中,把 keyword1和keyword2相 同
26. */
27. query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new
28. String[]{"title","content"},analyzer);
29.
30.
31. /** ** 两个(多个)关键 字对两个(多 个)字 段进行查询,手 工指定匹配规则 ****/
32. /*
33. * 1. 必须 关键字的个数 == 字 段名的个数 == 匹 配规则的个数
34. * 2.下面查询的意思是:"title"必 须不含有keyword1,并 且"content"中 必须含有 keyword2
35. */
36. BooleanClause.Occur[] flags = new
37. BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST};
38. query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new
39. String[]{"title","content"},flags,analyzer);
40.
41.
42. /** *** 对日期型字段进行查询 **** */
43.
44. /** *** 对数字范围进行查询 **** */
45. /*
46. * 1. 两个条件必须是同一个字段
47. * 2.前面一个条件必须比后面一个条件小,否则找不到数据
48. * 3.new RangeQuery中 的第三个参数,表示是否包含"=" true: >= 或 & lt;= false: > 或 <
49. * 4.找出 55>=id>=53 or 60>=id>=57:
50. */
51. Term lowerTerm1 = new Term("id","53");
52. Term upperTerm1 = new Term("id","55");
53. RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true);
54.
55. Term lowerTerm2 = new Term("id","57");
56. Term upperTerm2 = new Term("id","60");
57. RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true);
58.
59. BooleanQuery bq = new BooleanQuery();
60. bq.add(rq1,BooleanClause.Occur.SHOULD);
61. bq.add(rq2,BooleanClause.Occur.SHOULD);
62. Hits hits = searcher.search(bq);
1 、整体结构说明
索引和搜索过程图:
API 使用示例图:
1. 索引过程:
1) 有一系列被索引文件
2) 被索引文件经过语法分析和语言处理形成一系列词 (Term) 。
3) 经过索引创建形成词典和反向索引表。
4) 通过索引存储将索引写入硬盘。
2. 搜索过程:
a) 用户输入查询语句。
b) 对查询语句经过语法分析和语言分析得到一系列词 (Term) 。
c) 通过语法分析得到一个查询树。
d) 通过索引存储将索引读入到内存。
e) 利用查询树搜索索引,从而得到每个词 (Term) 的 文档链表,对文档链表进行交,差,并得到结果文档。
f) 将搜索到的结果文档对查询的相关性进行排序。
g) 返回查询结果给用户。
2 、基本使用说明
lucene 索引的单元对象是 Document, 它可以是一个文本、一封 email 或者一个网页等,其中 Document 包含多个 Field ,一个 Field 就是它的一个属性,比如“文件路径”、“作者”,“文件内容”等都是 Field
1 )索引用类:
Java代码
1. /**
2. * 对目录进行Lucene索引
3. * @author roy
4. *
5. */
6. public class Indexer {
7. private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引结果存放目录
8. private static String DATA_DIR = "G:\\ROY的各种笔记"; //被索引文件存放的目录
9.
10. /**
11. * 测试主函数
12. * @param args
13. * @throws Exception
14. */
15. public static void main(String[] args) throws Exception{
16. long start = new Date().getTime();
17. int numIndexed = index(new File(INDEX_DIR),new File(DATA_DIR));//调用index方法
18. long end = new Date().getTime();
19. System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
20. }
21.
22. /**
23. * 索引dataDir下的.txt文件,并储存在indexDir下,返回索引的文件数量
24. * @param indexDir
25. * @param dataDir
26. * @return
27. * @throws IOException
28. */
29. private static int index(File indexDir, File dataDir) throws Exception{
30. if(!dataDir.exists() || !dataDir.isDirectory()){
31. throw new Exception("被索引的文件不存在!");
32. }
33. if(!indexDir.exists() || !indexDir.isDirectory()){
34. indexDir.mkdirs();
35. }
36. IndexWriter writer = new IndexWriter(
37. FSDirectory.open(indexDir),
38. new StandardAnalyzer(Version.LUCENE_30),
39. true,
40. IndexWriter.MaxFieldLength.UNLIMITED
41. );
42. //按照目录进行递归索引
43. indexDirectory(writer,dataDir);
44. int numIndexed = writer.numDocs();
45. //对索引后的结果加以优化
46. writer.optimize();
47. writer.close();
48. return numIndexed;
49. }
50. /**
51. * 循环遍历目录下的所有.doc文件并进行索引
52. * @param writer
53. * @param dir
54. * @throws IOException
55. */
56. private static void indexDirectory(IndexWriter writer, File dir) throws IOException {
57. File[] files = dir.listFiles();
58. for (int i = 0; i < files.length; i++) {
59. File f = files[i];
60. if (f.isDirectory()) {
61. indexDirectory(writer, f); // recurse
62. } else if (f.getName().endsWith(".doc")) {
63. indexFile(writer, f);
64. }
65. }
66. }
67. /**
68. * 对单个doc文件进行索引
69. * @param writer
70. * @param f
71. * @throws IOException
72. */
73. private static void indexFile(IndexWriter writer, File f)
74. throws IOException {
75. if (f.isHidden() || !f.exists() || !f.canRead()) {
76. return;
77. }
78. System.out.println("Indexing " + f.getCanonicalPath());
79. Document doc = new Document();
80. doc.add(new Field("content",new FileReader(f)));
81. doc.add(new Field("filename",f.getName(),Field.Store.YES, Field.Index.ANALYZED));
82. doc.add(new Field("path",f.getCanonicalPath(),Field.Store.YES, Field.Index.ANALYZED));
83. writer.addDocument(doc);
84. }
85. }
/**
* 对目录进行Lucene索引
* @author roy
*
*/
public class Indexer {
private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引结果存放目录
private static String DATA_DIR = "G:\\ROY的各种笔记"; //被索引文件存放的目录
/**
* 测试主函数
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
long start = new Date().getTime();
int numIndexed = index(new File(INDEX_DIR),new File(DATA_DIR));//调用index方法
long end = new Date().getTime();
System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
}
/**
* 索引dataDir下的.txt文件,并储存在indexDir下,返回索引的文件数量
* @param indexDir
* @param dataDir
* @return
* @throws IOException
*/
private static int index(File indexDir, File dataDir) throws Exception{
if(!dataDir.exists() || !dataDir.isDirectory()){
throw new Exception("被索引的文件不存在!");
}
if(!indexDir.exists() || !indexDir.isDirectory()){
indexDir.mkdirs();
}
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexDir),
new StandardAnalyzer(Version.LUCENE_30),
true,
IndexWriter.MaxFieldLength.UNLIMITED
);
//按照目录进行递归索引
indexDirectory(writer,dataDir);
int numIndexed = writer.numDocs();
//对索引后的结果加以优化
writer.optimize();
writer.close();
return numIndexed;
}
/**
* 循环遍历目录下的所有.doc文件并进行索引
* @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(".doc")) {
indexFile(writer, f);
}
}
}
/**
* 对单个doc文件进行索引
* @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("content",new FileReader(f)));
doc.add(new Field("filename",f.getName(),Field.Store.YES, Field.Index.ANALYZED));
doc.add(new Field("path",f.getCanonicalPath(),Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
}
}
2 )查询用类:
Java代码
1. /**
2. * 对索引结果进行搜索
3. * @author roy
4. *
5. */
6. public class Searcher {
7. private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引所在的路径
8. private static String KEYWORD = "自己"; //关键词
9. private static int TOP_NUM = 100; //显示前100条结果
10. /**
11. * 测试主函数
12. * @param args
13. * @throws Exception
14. */
15. public static void main(String[] args) throws Exception{
16. File indexDir = new File(INDEX_DIR);
17. if (!indexDir.exists() || !indexDir.isDirectory()){
18. throw new Exception(indexDir + "索引目录不存在!");
19. }
20. search(indexDir,KEYWORD); //调用search方法进行查询
21. }
22. /**
23. * 索引查找方法
24. * @param indexDir 索引所在的目录
25. * @param q 查询的字符串
26. * @throws Exception
27. */
28. private static void search(File indexDir, String q) throws Exception {
29. IndexSearcher is = new IndexSearcher(FSDirectory.open(indexDir),true); //read-only
30. String field = "content";
31. //创建查询解析器
32. QueryParser parser = new QueryParser(Version.LUCENE_30, field, new StandardAnalyzer(Version.LUCENE_30));
33. Query query = parser.parse(q);
34. //创建结果收集器
35. TopScoreDocCollector collector = TopScoreDocCollector.create(TOP_NUM ,false);//有变化的地方
36.
37. long start = new Date().getTime();// start time
38. is.search(query, collector);
39. ScoreDoc[] hits = collector.topDocs().scoreDocs;
40.
41. System.out.println(hits.length);
42. for (int i = 0; i < hits.length; i++) {
43. Document doc = is.doc(hits[i].doc);//new method is.doc()
44. System.out.println(doc.getField("filename")+" "+hits[i].toString()+" ");
45. }
46. long end = new Date().getTime();//end time
47.
48. System.out.println("Found " + collector.getTotalHits() +
49. " document(s) (in " + (end - start) +
50. " milliseconds) that matched query '" +
51. q + "':");
52. }
53. }
/**
* 对索引结果进行搜索
* @author roy
*
*/
public class Searcher {
private static String INDEX_DIR = "G:\\ROY的各种笔记\\索引"; //索引所在的路径
private static String KEYWORD = "自己"; //关键词
private static int TOP_NUM = 100; //显示前100条结果
/**
* 测试主函数
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
File indexDir = new File(INDEX_DIR);
if (!indexDir.exists() || !indexDir.isDirectory()){
throw new Exception(indexDir + "索引目录不存在!");
}
search(indexDir,KEYWORD); //调用search方法进行查询
}
/**
* 索引查找方法
* @param indexDir 索引所在的目录
* @param q 查询的字符串
* @throws Exception
*/
private static void search(File indexDir, String q) throws Exception {
IndexSearcher is = new IndexSearcher(FSDirectory.open(indexDir),true); //read-only
String field = "content";
//创建查询解析器
QueryParser parser = new QueryParser(Version.LUCENE_30, field, new StandardAnalyzer(Version.LUCENE_30));
Query query = parser.parse(q);
//创建结果收集器
TopScoreDocCollector collector = TopScoreDocCollector.create(TOP_NUM ,false);//有变化的地方
long start = new Date().getTime();// start time
is.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
System.out.println(hits.length);
for (int i = 0; i < hits.length; i++) {
Document doc = is.doc(hits[i].doc);//new method is.doc()
System.out.println(doc.getField("filename")+" "+hits[i].toString()+" ");
}
long end = new Date().getTime();//end time
System.out.println("Found " + collector.getTotalHits() +
" document(s) (in " + (end - start) +
" milliseconds) that matched query '" +
q + "':");
}
}
3 )选择分词器:
分词器是一个搜索引擎的核心之一,好的分词器可以把关键字分解为更接近于用户的搜索目标的词汇。
下面的方法可以显示分词器的分词结果:
Java代码
1. /**
2. * 查看分词后的结果
3. * @param analyzer 分词器
4. * @param s 需要分词的字符串
5. * @throws Exception
6. */
7. public static void showAnalyzerResult(Analyzer analyzer, String s) throws Exception {
8. StringReader reader = new StringReader(s);
9. TokenStream tokenStream = analyzer.tokenStream(s,reader);
10. tokenStream.addAttribute(TermAttribute.class);
11.
12. while (tokenStream.incrementToken()) {
13. TermAttribute ta = tokenStream.getAttribute(TermAttribute.class);
14. System.out.println(ta.term());
15. }
16. System.out.println();
17. }
/**
* 查看分词后的结果
* @param analyzer 分词器
* @param s 需要分词的字符串
* @throws Exception
*/
public static void showAnalyzerResult(Analyzer analyzer, String s) throws Exception {
StringReader reader = new StringReader(s);
TokenStream tokenStream = analyzer.tokenStream(s,reader);
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute ta = tokenStream.getAttribute(TermAttribute.class);
System.out.println(ta.term());
}
System.out.println();
}
4 )索引doc,pdf等文件:
默认情况下 lucene 会索引 lucene 文件,其他文件直接索引会出现大量错误。所以我们需要对 doc,pdf 这些文件进行预处理,先生成 txt 文件才可。
1、doc文件:
先下载最新的POI组件,使用其中的poi-3.6-20091214.jar和poi- scratchpad-3.6-20091214即可实现读取word文件中的纯文本内容
Java代码
1. InputStream is = new FileInputStream(f);
2. WordExtractor wordExtractor = new WordExtractor(is);
3. return wordExtractor.getText();
InputStream is = new FileInputStream(f);
WordExtractor wordExtractor = new WordExtractor(is);
return wordExtractor.getText();
2、pdf文件:
下载最新的pdf-box,把fontbox-1.1.0.jar、jempbox-1.1.0.jar、pdfbox-1.1.0.jar三个包放进项目路径中
Java代码
1. InputStream is = new FileInputStream(f);
2. PDFTextStripper ts = new PDFTextStripper();
3. PDDocument pDocument = PDDocument.load(is);
4. StringWriter writer = new StringWriter();
5. ts.writeText(pDocument,writer);
6. is.close();
7. pDocument.close();
8. return writer.getBuffer().toString();
InputStream is = new FileInputStream(f);
PDFTextStripper ts = new PDFTextStripper();
PDDocument pDocument = PDDocument.load(is);
StringWriter writer = new StringWriter();
ts.writeText(pDocument,writer);
is.close();
pDocument.close();
return writer.getBuffer().toString();
5、查看当前索引库的内容
下载最新Luke工具,解压到lucene文件夹下,在命令行输入:
java -classpath lukeall-0.7.1.jar;lucene-2.0.jar org.getopt.luke.Luke
即可
5 )索引的添加、删除和更新:
1、添加新的索引记录
Java代码
1. IndexWriter writer = new IndexWriter(
2. FSDirectory.open(indexFile),
3. analyzer,
4. false,
5. IndexWriter.MaxFieldLength.UNLIMITED
6. );
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexFile),
analyzer,
false,
IndexWriter.MaxFieldLength.UNLIMITED
);
在创建索引器的时候指定create参数为true表示新建立索引,false表示使用当前目录下已有的索引。此时为writer添加 document并optimize()即可
2、删除索引
Java代码
1. /**
2. * 暂时删除某个索引
3. * @param f
4. * @throws Exception
5. */
6. public static void deleteIndexTmp(File indexFile,String targetPath) throws Exception{
7. IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
8. ir.deleteDocuments(new Term("path",targetPath));
9. ir.close();
10. }
11. /**
12. * 恢复某个临时删除的索引
13. * @param f
14. * @throws Exception
15. */
16. public static void rollbackDelete(File indexFile) throws Exception{
17. IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
18. ir.undeleteAll();
19. ir.close();
20. }
21. /**
22. * 将标记为删除的索引真正删除
23. * @param f
24. * @throws Exception
25. */
26. public static void optimizeIndex(File indexFile) throws Exception{
27. IndexWriter writer = new IndexWriter(
28. FSDirectory.open(indexFile),
29. analyzer,
30. false,
31. IndexWriter.MaxFieldLength.UNLIMITED
32. );
33. writer.optimize();
34. writer.close();
35. }
/**
* 暂时删除某个索引
* @param f
* @throws Exception
*/
public static void deleteIndexTmp(File indexFile,String targetPath) throws Exception{
IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
ir.deleteDocuments(new Term("path",targetPath));
ir.close();
}
/**
* 恢复某个临时删除的索引
* @param f
* @throws Exception
*/
public static void rollbackDelete(File indexFile) throws Exception{
IndexReader ir = IndexReader.open(FSDirectory.open(indexFile));
ir.undeleteAll();
ir.close();
}
/**
* 将标记为删除的索引真正删除
* @param f
* @throws Exception
*/
public static void optimizeIndex(File indexFile) throws Exception{
IndexWriter writer = new IndexWriter(
FSDirectory.open(indexFile),
analyzer,
false,
IndexWriter.MaxFieldLength.UNLIMITED
);
writer.optimize();
writer.close();
}
3、更新索引:
可以先查到旧索引将其删除,然后再新建索引即可。
Lucene3.0以后提供了新的update(Term,Document)方法,封装了上述两个操作。
6 )高级查询:
Java代码
1. /** *** 一个关键字,对一个字段进行查询 **** */
2. QueryParser qp = new QueryParser("content",analyzer);
3. query = qp.parse(keyword);
4. Hits hits = searcher.search(query);
5.
6. /** *** 模糊查询 **** */
7. Term term = new Term("content",keyword);
8. FuzzyQuery fq = new FuzzyQuery(term);
9. Hits hits = searcher.search(fq);
10.
11. /** *** 一个关键字,在两个字段中查询 **** */
12. /*
13. * 1.BooleanClause.Occur[] 的三种 类型: MUST : + and MUST_NOT : - not SHOULD : or
14. * 2.下面查询的意思是:content中 必须包含该关键字,而title有 没有都无所谓
15. * 3.下面的这个查询中,Occur[]的 长度必须和Fields[]的 长度一致。每个限制条件对应一个字段
16. */
17. BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};
18. query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer);
19.
20.
21. /** *** 两个(多个)关键 字对两个(多 个)字 段进行查询,默 认匹配规则 **** */
22. /*
23. * 1. 关键字的个数必须和字段的个数相等
24. * 2. 由于没有指定匹配规定,默认为"SHOULD" 因 此,下面查询的意思是:"title"中 含有keyword1 或 "content"含有 keyword2.
25. * 在此例中,把 keyword1和keyword2相 同
26. */
27. query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new
28. String[]{"title","content"},analyzer);
29.
30.
31. /** ** 两个(多个)关键 字对两个(多 个)字 段进行查询,手 工指定匹配规则 ****/
32. /*
33. * 1. 必须 关键字的个数 == 字 段名的个数 == 匹 配规则的个数
34. * 2.下面查询的意思是:"title"必 须不含有keyword1,并 且"content"中 必须含有 keyword2
35. */
36. BooleanClause.Occur[] flags = new
37. BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST};
38. query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new
39. String[]{"title","content"},flags,analyzer);
40.
41.
42. /** *** 对日期型字段进行查询 **** */
43.
44. /** *** 对数字范围进行查询 **** */
45. /*
46. * 1. 两个条件必须是同一个字段
47. * 2.前面一个条件必须比后面一个条件小,否则找不到数据
48. * 3.new RangeQuery中 的第三个参数,表示是否包含"=" true: >= 或 & lt;= false: > 或 <
49. * 4.找出 55>=id>=53 or 60>=id>=57:
50. */
51. Term lowerTerm1 = new Term("id","53");
52. Term upperTerm1 = new Term("id","55");
53. RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true);
54.
55. Term lowerTerm2 = new Term("id","57");
56. Term upperTerm2 = new Term("id","60");
57. RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true);
58.
59. BooleanQuery bq = new BooleanQuery();
60. bq.add(rq1,BooleanClause.Occur.SHOULD);
61. bq.add(rq2,BooleanClause.Occur.SHOULD);
62. Hits hits = searcher.search(bq);
发表评论
-
程序员到项目经理:从内而外的提升
2012-11-20 21:57 1071很不错的文章,看了有感触: http://www.manag ... -
25个免费的小清新风格的XHTML/CSS网站模板推荐
2013-08-17 10:54 922非常喜欢的风格: http://www.iteye.com ... -
如何带好新员工
2012-02-07 09:17 1202http://www.iteye.com/topic/1120 ... -
一线架构师:一
2012-01-30 10:42 970软件构架脑图: -
Freelancer
2012-01-10 13:35 1146自由骑士 http://www.52freelancer.c ... -
安装 Tokyo Cabinet 和 Tokyo Tyrant
2011-12-29 09:00 1238原文出处:http://blog.chenlb.com/200 ... -
大型电子商务网站架构之-前端优化
2011-12-21 14:23 1081http://liriguang.iteye.com/blog ... -
网站架构
2011-12-21 14:06 902业务分离,域名分离 一个业务对应一个系统、一 ... -
ext开发的统一办公平台
2011-12-05 13:31 851觉的不错,标记下 http://blog.csdn.net/ ... -
浅谈PM(好文推荐)
2011-11-10 14:27 544浅谈PM(不错的文章) http://www.itpub.n ... -
评估产品机会
2011-10-31 21:45 754评估产品机会 1. 产品要解决什么问题?(产品价值) ... -
WINDOWS下使用7z将文件打包压缩成tar.gz格式教程
2011-08-02 15:33 1759http://www.fuyahui.com/post/hel ... -
firfox关闭的时候不提示是否保存已打开的标签页解决方法
2011-07-07 16:50 864在地址栏中打开 about:config 在过滤器中输入 b ... -
Java集群之session共享解决方案
2011-06-29 23:53 1802转:http://blog.csdn.net/crskyp/a ... -
Clustering经典范文学习
2011-06-29 23:20 1168转:http://blog.csdn.net/calvinxi ... -
java常用网站收集
2011-04-18 14:04 828自己常去iteye 和 csdn ,一些活跃的java网站偶尔 ... -
JavaScript跨域总结与解决办法
2011-04-15 19:10 938转自:http://www.cnblogs.com ... -
如何将.class文件打成jar包
2011-04-01 23:31 1128转载自:http://blog.csdn.net/tomorr ... -
eclipse快捷键
2011-03-10 10:52 795首先键盘而非鼠标,高效程序员入门必备 Ctrl+1 快 ...
相关推荐
标题:Lucene学习笔记 描述:Lucene学习笔记,Lucene入门必备材料 知识点: 一、Lucene概述与文档管理策略 Lucene是一款高性能、全功能的文本搜索引擎库,广泛应用于文档检索、全文搜索等场景。为了提升搜索效率...
**Lucene 学习笔记 1** Lucene 是一个全文搜索引擎库,由 Apache 软件基金会开发。它提供了一个可扩展的、高性能的搜索框架,使得开发者能够在其应用程序中集成高级的搜索功能。本篇学习笔记将深入探讨 Lucene 的...
NULL 博文链接:https://kylinsoong.iteye.com/blog/719415
lucene学习笔记 1 .txt lucene学习笔记 2.txt lucene学习笔记 3 .txt lucene入门实战.txt Lucene 的学习 .txt Lucene-2.0学习文档 .txt Lucene入门与使用 .txt lucene性能.txt 大富翁全文索引和查询的例子...
10. **lucene学习笔记 3 .txt** 这是作者的学习笔记,可能包含了个人理解和使用Lucene过程中遇到的问题及解决方案,提供了不同角度的见解和实践经验。 通过这些文档,你可以系统地学习和掌握Lucene的各个方面,从...
【Lucene 3.6 学习笔记】 Lucene 是一个高性能、全文本搜索库,广泛应用于各种搜索引擎的开发。本文将深入探讨Lucene 3.6版本中的关键概念、功能以及实现方法。 ### 第一章 Lucene 基础 #### 1.1 索引部分的核心...
Lucene学习笔记(二)可能涉及索引构建过程,讲解了如何使用Document对象存储文档内容,Field对象定义字段属性,以及如何使用IndexWriter进行索引更新和优化。 笔记(三)和(四)可能深入到查询解析和执行。查询解析器...
### Lucene 3.5 学习笔记 #### 一、Lucene 3.5 基本概念 ##### 1.1 Lucene 概述 **1.1.1 IndexWriter** `IndexWriter` 是 Lucene 中的核心类之一,用于创建或更新索引。它提供了添加文档、删除文档、优化索引等...
Lucene学习笔记.doc nutch_tutorial.pdf nutch二次开发总结.txt nutch入门.pdf nutch入门学习.pdf Nutch全文搜索学习笔记.doc Yahoo的Hadoop教程.doc [硕士论文]_基于Lucene的Web搜索引擎实现.pdf [硕士论文]_基于...
Lucene 学习笔记是指如何学习和使用 Lucene。我们可以通过学习 Lucene 的使用和实现来掌握 Lucene。 Solr 学习笔记 Solr 学习笔记是指如何学习和使用 Solr。我们可以通过学习 Solr 的使用和实现来掌握 Solr。 ...
1> lucene学习笔记 2> 全文检索的实现机制 【1】lucene学习笔记的目录如下 1. 概述 3 2. lucene 的包结构 3 3. 索引文件格式 3 4. lucene中主要的类 4 4.1. Document文档类 4 4.1.1. 常用方法 4 4.1.2. 示例 4 4.2...