Lucene创建和搜索

来源:互联网 发布:最新3d公式计算法大全 编辑:程序博客网 时间:2024/04/29 22:17

Lucene的基本原理就是:先到数据库中取文章,创建索引文件,然后根据关键词到索引文件中取匹配的文章。

本文就先从创建索引开始:

我是直接创建一个控制台来跑的,然后调用一个线程,开始跑文章;我就直接从跑文章开始了:

文章数量太多了,所以我采用了一次跑10000篇文章的方式:

 public string Dojob()
        {
            try
            {
                int min = GetMinId();//数据库获取最小ID
                int max = GetMaxId();//数据库获取最大ID               
                string returnstr = "";
                for (int i = min; i < max; i += 10000)
                {
                    returnstr = returnstr + "\r\n" + CreatIndex(i);
                }          
                return returnstr;
            }
            catch (Exception ex)
            {
                return ex.ToString(); 
            }
        } 

            return indexts.ToString();
        }


public string CreatIndex(int i)
        {
            TimeSpan indexts = new TimeSpan();
            try
            {
                DateTime starttime = DateTime.Now;

//创建字典,打开索引文件的存储位置,为写文章做准备
                Lucene.Net.Store.FSDirectory directory = Lucene.Net.Store.FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH), new NativeFSLockFactory());
                //IndexReader:对索引库进行读取的类
                bool isExist = IndexReader.IndexExists(directory); //是否存在索引库文件夹以及索引库特征文件
                if (isExist)
                {
                    //如果索引目录被锁定(比如索引过程中程序异常退出或另一进程在操作索引库),则解锁
                    //Q:存在问题 如果一个用户正在对索引库写操作 此时是上锁的 而另一个用户过来操作时 将锁解开了 于是产生冲突 --解决方法后续
                    if (IndexWriter.IsLocked(directory))
                    {
                        IndexWriter.Unlock(directory);
                    }                    
                }                
                //创建向索引库写操作对象  IndexWriter(索引目录,指定使用盘古分词进行切词,最大写入长度限制)
                //补充:使用IndexWriter打开directory时会自动对索引库文件上锁//相当于创建一支写的笔和写在哪里

                IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isExist, IndexWriter.MaxFieldLength.UNLIMITED);
                var strList = this.GetArticles(i);//根据i到数据库取ID为(i-1)*10000到i*10000之间的文章
                foreach (var book in strList)
                {
                    Document document = new Document(); //new一篇文档对象 --一条记录对应索引库中的一个文档
                    ////向文档中添加字段  Add(字段,值,是否保存字段原始值,是否针对该列创建索引)                  
                    document.Add(new Field("content", book, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
                    writer.AddDocument(document); //文档写入索引库
                }
                writer.Close();//会自动解锁
                directory.Close(); //不要忘了Close,否则索引结果搜不到
                DateTime endttime = DateTime.Now;
                indexts = endttime - starttime;
            }           
            catch (Exception ex)
            {
                return ex.ToString(); 
            }

}

掺杂一些数据库的处理,生成索引库就完成了,下面根据关键词来进行文章匹配。


 public string GetBestAricle(string keystr)
        {
            string fangfang = "";
            ReturnArticle result = new ReturnArticle();
            string Beststr = "";       //文章,这个字符串会包含一些我需要的文章id,文章标题等等信息,在建索引的时候包含进去
            try
            {            
                DateTime starttime = DateTime.Now;

//打开索引文件所在目录
                FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH), new NoLockFactory());
                IndexReader reader = IndexReader.Open(directory, false);
                IndexSearcher searcher = new IndexSearcher(reader);
                //搜索条件            
                BooleanQuery query=new BooleanQuery();
                //把用户输入的关键字进行分词
                var KeyList = SplitWords(keystr);
                string str = "";
                for  (int i=0;i<KeyList.Length;i++)
                {                   
                    Query query1 = new TermQuery(new Term("content", KeyList[i]));
                    if (i == 0)
                    {
                        query.Add(query1, BooleanClause.Occur.MUST);
                        str = str + KeyList[i];
                    }
                    else
                    {//这里存在一个关键点,如果分词存在两个相同或者包含的词的话,文章匹配结果基本上没有任何作用
                        if (!str.Contains(KeyList[i]))
                        { 
                            query.Add(query1, BooleanClause.Occur.MUST_NOT);
                            str = str + KeyList[i];
                        }
                    }
                        
                }       
                TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
                searcher.Search(query, null, collector);//根据query查询条件进行查询,查询结果放入collector容器
                //TopDocs 指定0到GetTotalHits() 即所有查询结果中的文档 如果TopDocs(20,10)则意味着获取第20-30之间文档内容 达到分页的效果
                ScoreDoc[] docs = collector.TopDocs(0, 50).scoreDocs;//collector.GetTotalHits()
                //Beststr = docs[0].Get("content");
                for (int i = 0; i < docs.Length; i++)
                {
                    int docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id)
                    Document doc = searcher.Doc(docId);//根据文档id来获得文档对象Document
                    //book.ContentDescription = doc.Get("content");//未使用高亮
                    //搜索关键字高亮显示 使用盘古提供高亮插件
                    Beststr = doc.Get("content");
                    string[] mostr = Beststr.Split('@');//以@作为分隔符
                    fangfang += mostr[0].ToString();
                    if (Beststr.Length > 100)
                    {//取50个字符串数据库模糊查询,如果存在跳下一条,否则继续
                        string word = Beststr.Substring(20,70);
                        if (IsRepeat(word))
                            break;
                        reader.DeleteDocument(docId);
                       
                    }
                    //后续写到数据库中
                }
                reader.Close();
            }
            catch (Exception ex)
            {
                throw (ex);
            }
            return Beststr; 
        }

     public static string[] SplitWords(string content)
        {
            StringReader sb = new StringReader(content);  
            List<string> strList = new List<string>();
            Analyzer analyzer = new PanGuAnalyzer(); ;//指定使用盘古 PanGuAnalyzer 分词算法
            TokenStream tokenStream = analyzer.TokenStream("", sb);
            Lucene.Net.Analysis.Token token = null;          
           // bool hasNext = tokenStream.IncrementToken();            
            while ((token = tokenStream.Next()) != null)
            //while(hasNext)
            { //Next继续分词 直至返回null
               // token =tokenStream.GetAttribute<Lucene.Net.Analysis.Tokenattributes.ITermAttribute>();;
                strList.Add(token.TermText()); //得到分词后结果
               // hasNext = tokenStream.IncrementToken();
            }
            return strList.ToArray();
        }       


0 0
原创粉丝点击