Lucene索引创建及使用方法

Lucene创建及使用方法

1.1 Lucene简介

Lucene.NET是一个全文搜索框架,,lucene的功能很单一,说到底,就是你给它若干个字符串,然后它为你提供一个全文搜索服务,告诉你你要搜索的关键词出现在哪里。知道了这个本质,你就可以发挥想象做任何符合这个条件的事情了。你可以把站内新闻都索引了,做个资料库;你可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁表了。

1.2 lucene的工作方式

lucene提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务,让用户可以通过关键词定位源。

用通俗的话讲就是:先创建索引,再从索引读取想要的数据。

A.   写入流程:即创建索引

一、            首先实例化一个构造器

 

  IndexWriter writer  =   new  IndexWriter( " D:/index/ " new  PanGuAnalyzer(),  true );    // 索引的存储位置  

 

这个构造函数具有三个参数:

1.      path:索引文件存放的路径。如:String path = "E:\\index";

2.      a:分词工具,因为lucene为外国人所开发,所以对中文分词不是很友好,但人类的智慧是无穷的,这里引入盘古分词,专门针对中文的分词。如:a= new PanGuAnalyzer(),盘古分词官网http://pangusegment.codeplex.com/

3.      create:它是一个boolean型变量,如果为true,表示要重写指定的存放索引目录下的索引文件;如果为false,表示在指定存放索引目录下已经存在的索引文件的基础上,向其中继续追加新的索引文件。

二、            创建索引

第一步并未创建索引,只是实例化了一个索引器,建立索引的过程是在一个IndexWriter索引器实例存在的前提下,通过为其添加Document,这样才能真正添加索引。

代码如下:

 

View Code
foreach  (var item  in  productlist)
            {
                Document doc 
=   new  Document();
                doc.Add(
new  Field( " id " , item.id.ToString(), Field.Store.YES, Field.Index.UN_TOKENIZED)); // 其中ID、Name、Add都是数据库中的字段名,这个应该可以看明白的吧  
                doc.Add( new  Field( " productname " , item.productname, Field.Store.YES, Field.Index.TOKENIZED));
                doc.Add(
new  Field( " productdes " , item.productdes, Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(
new  Field( " tradename " , item.tradename, Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(
new  Field( " companyname " , item.companyname, Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(
new  Field( " fhdes " , item.fhdes, Field.Store.YES, Field.Index.TOKENIZED));
                doc.Add(
new  Field( " pic " , item.pic, Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(
new  Field( " areaname " , item.areaname, Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(
new  Field( " tradeid " , item.tradeid.ToString(), Field.Store.YES, Field.Index.UN_TOKENIZED));
                writer.AddDocument(doc);
            }

 

 

看完上面的代码先引入几个概念

1.      Field:可以理解成索引文件中一个个的字段块,占用空间按字段长度分配。

2.      Store:一个内部类,它是static的,主要为了设置Field的存储属性.

 

public  static final Store COMPRESS =  new Store( " COMPRESS ");  //  在索引中压缩存储Field的值
 
public  static final Store YES =  new Store( " YES "); // 在索引中存储Field的值
 
public  static final Store NO =  new Store( " NO ");  //  在索引中不存储Field的值

3.      Index: 通过Index设置索引方式,,不对Field进行索引,所以这个Field就不能被检索到(一般来说,建立索引而使它不被检索,这是没有意义的),如果对该Field还设置了Field.StoreField.Store.YESField.Store.COMPRESS,则可以检索

 

public  static final Index TOKENIZED =  new Index( " TOKENIZED ");  //  对Field进行索引,同时还要对其进行分词(由Analyzer来管理如何分词)
 
public  static final Index UN_TOKENIZED =  new Index( " UN_TOKENIZED ");  //  对Field进行索引,但不对其进行分词
 
public  static final Index NO_NORMS =  new Index( " NO_NORMS ");  //  对Field进行索引,但是不使用Analyzer

 

三、            优化索引,关闭写入

 

writer.Optimize();  // 添加完所有document,我们对索引进行优化,优化主要是将多个索引文件合并到一个,有利于提高索引速度。 

writer.Close(); // 随后将writer关闭,这点很重要。

 

B.   读出流程(即使用索引)

1.       创建一个容器来存放你从索引文件中读取到的数据,这里我们使用Table

   private  DataTable dt()
        {
            DataTable mytab 
=   new  DataTable();
            mytab.Columns.Add(
" ID " );
            mytab.Columns.Add(
" TRADENAME " );
            mytab.Columns.Add(
" AREANAME " );
            mytab.Columns.Add(
" COMPANYNAME " );
            mytab.Columns.Add(
" FHDES " );
            mytab.Columns.Add(
" PRODUCTNAME " );
            mytab.Columns.Add(
" PIC " );
            mytab.Clear();
            
return  mytab;
        }

 

 

2.       读取索引文件中的数据

 

  private  IndexSearcher LuceneSource()
        {
            
string  INDEX_STORE_PATH  =   " D:/index/ " ;   // INDEX_STORE_PATH 为索引存储目录   
             return   new  IndexSearcher(INDEX_STORE_PATH);
        }

 

3.       这一步我们需要得到过滤后数据,即查询条件,你可以理解成SQL里的where条件

lucene的搜索相当强大,它提供了很多辅助查询类,每个类都继承自Query类,各自完成一种特殊的查询,你可以像搭积木一样将它们任意组合使用,完成一些复杂操作;另外lucene还提供了Sort类对结果进行排序,提供了Filter类对查询条件进行限制。你或许会不自觉地拿它跟SQL语句进行比较:“lucene能执行andororder bywherelike%xx%’操作吗?”回答是:“当然没问题!”

a.       TermQuery

首先介绍最基本的查询,如果你想执行一个这样的查询:content域中包含‘lucene’document”,那么你可以用TermQuery

Term t  =   new  Term( " content " "  lucene " );Query query  =   new  TermQuery(t);

 

b.       BooleanQuery

如果你想让产品名称或者产品发货说明匹配关键字,那么你可以用:

 

                strkeyword = Common.ProductAbout.GetKeyWordsSplitBySpace(strkeyword,  new PanGuTokenizer());
                QueryParser companynameparser =  new QueryParser( " companyname "new PanGuAnalyzer( true));
                Query companynamequery = companynameparser.Parse(strkeyword);
                QueryParser productnameparser =  new QueryParser( " productname "new PanGuAnalyzer( true));
                Query productdesquery = productnameparser.Parse(strkeyword);
                bq.Add(productdesquery, BooleanClause.Occur.SHOULD);
                bq.Add(companynamequery, BooleanClause.Occur.SHOULD);

 

Tip:清单此处的BooleanClause.Occur,此类有2个重要的属性,SHOULDMUSTSHOULD你就理解成SQL’OR’MUST理解成SQL里的’AND’,此处表示要同时满足productdesqueryidquery

 

 

c.      WildcardQuery

如果你想对某单词进行通配符查询,你可以用WildcardQuery,通配符包括’?’匹配一个任意字符和’*’匹配零个或多个任意字符,例如你搜索’use*’,你可能找到’useful’或者’useless’:

Query query  =   new  WildcardQuery( new  Term( " content " " use* " );

 

d.      PhraseQuery

你可能对中日关系比较感兴趣,想查找挨得比较近(5个字的距离内)的文章,超过这个距离的不予考虑,你可以:

PhraseQuery query  =   new  PhraseQuery();
query.setSlop(
5 );query.add( new  Term( " content  " " " ));
query.add(
new  Term( " content " " " ));

 

那么它可能搜到中日合作……”中方和日方……”,但是搜不到中国某高层领导说日本欠扁

e.    PrefixQuery

如果你想搜以‘中’开头的词语,你可以用PrefixQuery

PrefixQuery query  =   new  PrefixQuery( new  Term( " content  " " " );

 

f.    FuzzyQuery

FuzzyQuery用来搜索相似的term,使用Levenshtein算法。假设你想搜索跟‘wuzza’相似的词语,你可以:

Query query  =   new  FuzzyQuery( new  Term( " content " " wuzza " );

 

你可能得到‘fuzzy’和‘wuzzy’。

g.    RangeQuery

另一个常用的QueryRangeQuery,你也许想搜索时间域从2006010120060130之间的document,你可以用RangeQuery

RangeQuery query  =   new  RangeQuery( new  Term(“time”, “ 20060101 ”),  new  Term(“time”, “ 20060130 ”),  true );

 

最后的true表示含边界。

4.       取得从索引文件中过滤后的数据

 

  private  Hits LuceneFilteridSource(BooleanQuery bq)
        {

            IndexSearcher mysearch 
=  LuceneSource();
            Sort sort 
=   new  Sort( new  SortField( " ID " , SortField.DOC,  false )); // 排序  
             return  mysearch.Search(bq, sort);

        }

 

Sort是对数据进行排序,比如这里对ID

进行排序.

 

注意,LUCENE不支持关键词为空的情况,所以如果你想把索引文件中所有的数据都调用出来,那可以用如下方法

 

  for  ( int  i  =   0 ; i  <  mysearch.MaxDoc(); i ++ )
                {
                    Document doc 
=  mysearch.Doc(i);
                    FillingTable(mytab, doc);
                }

 

5.       把过滤后的数据并扔入Table数据源

View Code
   private   void  FillingTable(DataTable dt, Document doc)
        {
            DataRow myrow;
            myrow 
=  dt.NewRow();
            myrow[
0 =  doc.Get( " id " ).ToString();
            myrow[
1 =  doc.Get( " tradename " ).ToString();
            myrow[
2 =  doc.Get( " areaname " ).ToString();
            myrow[
3 =  doc.Get( " companyname " ).ToString();
            myrow[
4 =  doc.Get( " fhdes " ).ToString();
            myrow[
5 =  doc.Get( " productname " ).ToString();
            myrow[
6 =  doc.Get( " pic " ).ToString();
            dt.Rows.Add(myrow);
            myrow.AcceptChanges();
        }

 

6.       OK,得到了table数据源,你可以在此基础上任意使用这些数据了。

 

 

你可能感兴趣的:(Lucene)