博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lucene资料汇总
阅读量:7153 次
发布时间:2019-06-29

本文共 6969 字,大约阅读时间需要 23 分钟。

本文来源于:

其他参考资料:

一、本文介绍了什么是Lucene,Lucene能做什么.

What’s Lucene Lucene是一个信息检索的函数库(Library),利用它你可以为你的应用加上索引和搜索的功能.

Lucene的使用者不需要深入了解有关全文检索的知识,仅仅学会使用库中的一个类,你就为你的应用实现全文检索的功能.

不过千万别以为Lucene是一个象google那样的搜索引擎,Lucene甚至不是一个应用程序,它仅仅是一个工具,一个Library.你也可以把它理解为一个将索引,搜索功能封装的很好的一套简单易用的API.利用这套API你可以做很多有关搜索的事情,而且很方便.

What Can Lucene Do

Lucene可以对任何的数据做索引和搜索. Lucene不管数据源是什么格式,只要它能被转化为文字的形式,就可以被Lucene所分析利用.也就是说不管是MS word, Html ,pdf还是其他什么形式的文件只要你可以从中抽取出文字形式的内容就可以被Lucene所用.你就可以用Lucene对它们进行索引以及搜索.

How To Use Lucene --- A Simple Example 示例介绍:

为作为输入参数的文件夹下的所有txt类型的文件做索引,做好的索引文件放入index文件夹.

然后在索引的基础上对文件进行全文搜索.

1.       建立索引

 

IndexWriter writer
=
new
IndexWriter(
"
index
"
,
new
StandardAnalyzer(),
true
); IndexDocs(writer,
new
System.IO.FileInfo(args[
0
]));                writer.Optimize(); writer.Close();

IndexWriter是对索引进行写操作的一个类,利用它可以创建一个索引对象然后往其中添加文件.需要注意它并不是唯一可以修改索引的类.在索引建好后利用其他类还可以对其进行修改.

构造函数第一个参数是建立的索引所要放的文件夹的名字.第二个参数是一个分析对象,主要用于从文本中抽取那些需要建立索引的内容,把不需要参与建索引的文本内容去掉.比如去掉一些a the之类的常用词,还有决定是否大小写敏感.不同的选项通过指定不同的分析对象控制.第三个参数用于确定是否覆盖原有索引的.

第二步就是利用这个writer往索引中添加文件.具体后面再说.

第三步进行优化.

第四步关闭writer.

 

下面具体看看第二步:

 

 

 
public
static
void
IndexDirectory(IndexWriter writer, FileInfo file)         
{               if (Directory.Exists(file.FullName))               {                    String[] files = Directory.GetFileSystemEntries(file.FullName);                    // an IO error could occur                    if (files !=null)                    {                        for (int i =0; i < files.Length; i++)                        {                             IndexDirectory(writer, new FileInfo(files[i]));  //这里是一个递归                        }                    }               }               elseif (file.Extension ==".txt")               {                    IndexFile(file, writer);               }          }
          
private
static
void
IndexFile(FileInfo file, IndexWriter writer)         
{               Console.Out.WriteLine("adding "+ file);               try               {                    Document doc =new Document();                                       doc.Add(Field.Keyword("filename", file.FullName));                    doc.Add(Field.Text("contents", new StreamReader(file.FullName)));                    writer.AddDocument(doc);               }                              catch (FileNotFoundException fnfe)               {                                   }      }

主要就是两个函数一个用于处理文件夹(不是为文件夹建立索引),一个用于真正为文件建立索引.

因此主要集中看一下IndexFile这个方法.首先建立Document对象,然后为Document对象添加一些属性Field.你可以把Document对象看成是虚拟文件,将来将从此获取信息.而Field则看成是描述此虚拟文件的元数据(metadata).

其中Field包括四个类型:

Keywork

该类型的数据将不被分析,而会被索引并保存保存在索引中.
UnIndexed 该类型的数据不会被分析也不会被索引,但是会保存在索引.
UnStored 和UnIndexed刚好相反,被分析被索引,但是不被保存.
Text 和UnStrored类似.如果值的类型为string还会被保存.如果值的类型为Reader就不会被保存和UnStored一样.

 

最后将每一个Document添加到索引当中.

需要注意的是索引不仅可以建立在文件系统上,也可以建立在内存中.

例如

IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);

在第一个参数不是指定文件夹的名字而是使用Directory对象,并使用它的子类RAMDirectory,就可以将索引建立在内存当中.

2.       对索引进行搜索

IndexSearcher indexSearcher
=
new
IndexSearcher(indexDir); Query query
=
QueryParser.Parse(queryString,
"
contents
"
,
new
StandardAnalyzer()); Hits hits
=
indexSearcher.Search(query);

第一步利用IndexSearcher打开索引文件用于后面搜索,其中的参数是索引文件的路径.

第二步使用QueryParser将可读性较好的查询语句(比如查询的词lucene ,以及一些高级方式lucene AND .net)转化为Lucene内部使用的查询对象.

第三步执行搜索.并将结果返回到hits集合.需要注意的是Lucene并不是一次将所有的结果放入hits中而是采取一次放一部分的方式.出于空间考虑.

至此,本文演示了如何从一个文件夹下的所有txt文件中查找特定的词。并围绕该个实例介绍了lucene.net的索引的建立以及如何针对索引进行搜索

 

二、Lucene建立Index的过程:

  1. 1.        抽取文本.

比如将PDF以及Word中的内容以纯文本的形式提取出来.Lucene所支持的类型主要为String,为了方便同时也支持Date 以及Reader.其实如果使用这两个类型lucene会自动进行类型转换.

  1. 2.        文本分析.

Lucene将针对所给的文本进行一些最基本的分析,并从中去除一些不必要的信息,比如一些常用字a ,an, the 等等,如果搜索的时候不在乎字母的大小写, 又可以去掉一些不必要的信息.总而言之你可以把这个过程想象成一个文本的过滤器,所有的文本内容通过分析, 将过滤掉一些内容,剩下最有用的信息.

  1. 3.        写入index.

google等常用的索引技术一样lucene在写index的时候都是采用的倒排索引技术(inverted index.) 简而言之,就是通过某种方法(类似hash?)将常见的一篇文档中含有哪些词这个问题转成哪篇文档中有这些词”. 而各个搜索引擎的索引机制的不同主要在于如何为这张倒排表添加更准确的描述.比如google有名的PageRank因素.Lucene当然也有自己的技术,希望在以后的文章中能为大家加以介绍.

 

在上一篇文章中,使用了最基本的建立索引的方法.在这里将对某些问题加以详细的讨论.

 

1. 添加Document至索引

上次添加的每份文档的信息是一样的,都是文档的filenamecontents.

doc.Add(Field.Keyword("filename", file.FullName)); doc.Add(Field.Text("contents", new StreamReader(file.FullName)));

Lucene中对每个文档的描述是可以不同的,比如,两份文档都是描述一个人,其中一个添加的是name, age 另一个添加的是id, sex ,这种不规则的文档描述在Lucene中是允许的.

 

 

还有一点Lucene支持对Field进行Append , 如下:

 

 

 

string baseWord = "fast";
  string synonyms[] = String {"quick", "rapid", "speedy"}; Document doc = new Document(); doc.Add(Field.Text("word", baseWord));
  for (int i = 0; i < synonyms.length; i++)      doc.Add(Field.Text("word", synonyms[i]));

这点纯粹是为了方便用户的使用.在内部Lucene自动做了转化,效果和将它们拼接好再存是一样.

 

2. 删除索引中的文档

这一点Lucene所采取的方式比较怪,它使用IndexReader来对要删除的项进行标记,然后在Reader Close的时候一起删除.

这里简要介绍几个方法.

[TestFixture] public class DocumentDeleteTest : BaseIndexingTestCase   // BaseIndexingTestCase中的SetUp方法                                                   //建立了索引其中加入了两个Document {      [Test]      public void testDeleteBeforeIndexMerge()      {               IndexReader reader = IndexReader.Open(dir);  //当前索引中有两个Document           Assert.AreEqual(2, reader.MaxDoc());   //文档从0开始计数,MaxDoc表示下一个文档的序号          Assert.AreEqual(2, reader.NumDocs());  //NumDocs表示当前索引中文档的个数           reader.Delete(1);                    //对标号为1的文档标记为待删除,逻辑删除          Assert.IsTrue(reader.IsDeleted(1));         //检测某个序号的文档是否被标记删除          Assert.IsTrue(reader.HasDeletions());       //检测索引中是否有Document被标记删除          Assert.AreEqual(2, reader.MaxDoc());        //当前下一个文档序号仍然为2          Assert.AreEqual(1, reader.NumDocs());       //当前索引中文档数变成1          reader.Close();                             //此时真正从物理上删除之前被标记的文档          reader = IndexReader.Open(dir);          Assert.AreEqual(2, reader.MaxDoc());                   Assert.AreEqual(1, reader.NumDocs());          reader.Close();      }       [Test]      public void DeleteAfterIndexMerge()            //在索引重排之后      {          IndexReader reader = IndexReader.Open(dir);          Assert.AreEqual(2, reader.MaxDoc());          Assert.AreEqual(2, reader.NumDocs());          reader.Delete(1);          reader.Close();          IndexWriter writer = new IndexWriter(dir, GetAnalyzer(), false);          writer.Optimize();                          //索引重排          writer.Close();          reader = IndexReader.Open(dir);          Assert.IsFalse(reader.IsDeleted(1));          Assert.IsFalse(reader.HasDeletions());          Assert.AreEqual(1, reader.MaxDoc());       //索引重排后,下一个文档序号变为1          Assert.AreEqual(1, reader.NumDocs());          reader.Close();      } }

当然你也可以不通过文档序号进行删除工作.采用下面的方法,可以从索引中删除包含特定的内容文档.

 

 

 

 

IndexReader reader = IndexReader.Open(dir); reader.Delete(new Term("city", "Amsterdam")); reader.Close();

你还可以通过reader.UndeleteAll()这个方法取消前面所做的标记,即在read.Close()调用之前取消所有的删除工作.

 

 

3. 更新索引中的文档

这个功能Lucene没有支持, 只有通过删除后在添加来实现. 看看代码,很好理解的.

 

 

 

 

[TestFixture] public class DocumentUpdateTest : BaseIndexingTestCase {      [Test]      public void Update()      {          Assert.AreEqual(1, GetHitCount("city", "Amsterdam"));          IndexReader reader = IndexReader.Open(dir);          reader.Delete(new Term("city", "Amsterdam"));          reader.Close();          Assert.AreEqual(0, GetHitCount("city", "Amsterdam"));          IndexWriter writer = new IndexWriter(dir, GetAnalyzer(),false);          Document doc = new Document();          doc.Add(Field.Keyword("id", "1"));          doc.Add(Field.UnIndexed("country", "Netherlands"));          doc.Add(Field.UnStored("contents","Amsterdam has lots of bridges"));          doc.Add(Field.Text("city", "Haag"));          writer.AddDocument(doc);          writer.Optimize();          writer.Close();          Assert.AreEqual(1, GetHitCount("city", "Haag"));      }        protected override Analyzer GetAnalyzer()      {          return new WhitespaceAnalyzer();  //注意此处如果用SimpleAnalyzer搜索会失败      }        private int GetHitCount(String fieldName, String searchString)      {          IndexSearcher searcher = new IndexSearcher(dir);          Term t = new Term(fieldName, searchString);          Query query = new TermQuery(t);          Hits hits = searcher.Search(query);          int hitCount = hits.Length();          searcher.Close();          return hitCount;      } }

 

 

 

 

 

需要注意的是以上所有有关索引的操作,为了避免频繁的打开和关闭WriterReader.又由于添加和删除是不同的连接(Writer, Reader)做的.所以应该尽可能的将添加文档的操作放在一起批量执行,然后将删除文档的操作也放在一起批量执行.避免添加删除交替进行.

转载于:https://www.cnblogs.com/honzhez/p/3287988.html

你可能感兴趣的文章
防DNS劫持教程,手动修复本地DNS教程
查看>>
java8_api_net
查看>>
wget: command not found
查看>>
C#九九乘法表的算法
查看>>
开篇:解决IE9字体模糊的问题(又称无法关闭ClearType)
查看>>
Oracle知识补充
查看>>
Javascript截取字符串方法集合
查看>>
软件项目质量保证——编码规范
查看>>
import static和import的区别
查看>>
android中Invalidate和postInvalidate的区别
查看>>
hive load from hdfs出错
查看>>
IOS开发:xcode5版本引发的问题
查看>>
亿级数据时,内存性能低于IO性能
查看>>
asp.net 负载均衡下session存储的解决方法
查看>>
构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(17)-LinQ动态排序
查看>>
Yii框架操作数据库的几种方式与mysql_escape_string
查看>>
公有云与私有云的差别(转)
查看>>
jQuery插件:jqGrid使用(一)
查看>>
mac显示隐藏文件
查看>>
FastDFS的配置、部署与API使用解读(6)FastDFS配置详解之Storage配置(转)
查看>>