Lucene.Net 与 盘古分词

时间:2020-12-02 03:06:22

1.关键的一点,Lucene.Net要使用3.0下面的版本号,否则与盘古分词接口不一致。
关键代码例如以下

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Analysis.PanGu;
using Maticsoft.DBUtility;
using System.Data;
using System.Diagnostics;
namespace SearchSentence
{
    class Program
    {

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


        public static void CreateIndex(string strDirectory)
        {

            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(strDirectory), 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);


            DataSet ds = DbHelperSQL.Query("select * from dbo.Sentences", 100);
            DataTable dt = ds.Tables[0];
            int rowsCount = dt.Rows.Count;
            for (int n = 0; n < rowsCount; n++)
            {

                if (dt.Rows[n]["Id"].ToString() != "" && dt.Rows[n]["TextZh"].ToString() != "")
                {
                    //--------------------------------遍历数据源 将数据转换成为文档对象 存入索引库
                    Document document = new Document(); //new一篇文档对象 --一条记录相应索引库中的一个文档

                    //向文档中加入字段  Add(字段,值,是否保存字段原始值,是否针对该列创建索引)
                    document.Add(new Field("id", dt.Rows[n]["Id"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//--全部字段的值都将以字符串类型保存 由于索引库仅仅存储字符串类型数据

                    //Field.Store:表示是否保存字段原值。

指定Field.Store.YES的字段在检索时才干用document.Get取出原值 //Field.Index.NOT_ANALYZED:指定不依照分词后的结果保存--是否按分词后结果保存取决于是否对该列内容进行模糊查询 document.Add(new Field("TextZh", dt.Rows[n]["TextZh"].ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS)); //Field.Index.ANALYZED:指定文章内容依照分词后结果保存 否则无法实现兴许的模糊查询 //WITH_POSITIONS_OFFSETS:指示不仅保存切割后的词 还保存词之间的距离 //document.Add(new Field("content", "我常常出去玩", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS)); writer.AddDocument(document); //文档写入索引库 Console.Write("{0}\r", n+1); } } writer.Close();//会自己主动解锁 directory.Close(); //不要忘了Close,否则索引结果搜不到 } public static void Query(string strQuery) { Stopwatch sw = new Stopwatch(); sw.Start(); FSDirectory directory = FSDirectory.Open(new DirectoryInfo("CH-EG"), new NoLockFactory()); IndexReader reader = IndexReader.Open(directory, true); IndexSearcher searcher = new IndexSearcher(reader); //搜索条件 PhraseQuery query = new PhraseQuery(); //把用户输入的关键字进行分词 foreach(string word in SplitWords(strQuery)) { query.Add(new Term("TextZh", word)); } //query.Add(new Term("content", "C#"));//多个查询条件时 为且的关系 query.SetSlop(100); //指定关键词相隔最大距离 //TopScoreDocCollector盛放查询结果的容器 TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true); searcher.Search(query, null, collector);//依据query查询条件进行查询,查询结果放入collector容器 sw.Stop(); //TopDocs 指定0到GetTotalHits() 即全部查询结果中的文档 假设TopDocs(20,10)则意味着获取第20-30之间文档内容 达到分页的效果 ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs; //展示数据实体对象集合 for (int i = 0; i < docs.Length; i++) { int docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id) Document doc = searcher.Doc(docId);//依据文档id来获得文档对象Document Console.Write("{0}\n", doc.Get("TextZh")); } TimeSpan ts2 = sw.Elapsed; Console.WriteLine("本次查询总共花费{0}ms.\n", ts2.TotalMilliseconds); } static void Main(string[] args) { //CreateIndex("CH-EG"); Console.Write("Press phrase: \n"); string strQuery = Console.ReadLine(); while (strQuery != "") { Query(strQuery); Console.Write("Press phrase: \n"); strQuery = Console.ReadLine(); } } } }

Demo下载地址 http://download.csdn.net/detail/lampqiu/8909427