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();
}
}
}
}