ASP.NETC#实现搜索功能
描述:我们现在开发的项⽬中⼏乎都会有搜索的这个需求,就像我们平时⽤的百度,⾕歌这些都是满⾜我们平时的搜索需求的。当然在我们的项⽬中我们不可能利⽤百度,⾕歌的搜索来实现⾃⼰项⽬中的搜索的,这时我们就需要⾃⼰进⾏开发实现这项功能了。那么怎样实现呢,其实现在现在我们有很多成熟的搜索算法,不必⾃⼰去研究,只需要⾃⼰修改那些⼤神写的代码就Ok啦。⾔归正传,下⾯介⼊正题。
搜索的功能我是⽤Lucene.Net和盘古分词⼆者的结合实现的。后⾯我会把相关的插件上传⼤家可以下载。
什么是Lucene.Net:
Lucene.Net是由Java版本的Lucene(卢思银)移植过来的,所有的类和⽅法都是和Lucene⾥的⼏乎⼀模⼀样。Lucene.Net只是⼀个全⽂检索开发包,不是⼀个成型的搜索引擎,它的功能就是把数据扔给Lucene.Net,我们查询数据的时候从Lucene.Net查询数据,可以将它看为⼀个全⽂检索的数据库。⽤户可以基于Lucene.Net开发满⾜⾃⼰的需求搜索引擎。Lucene.Net只能对⽂本信息进⾏检索,如果不是⽂本信息就需要转换为⽂本信息。(⽐如:要检索Excle⽂件,就要⽤NPO把Excle⽂件读取成字符串,然后把字符串交给Lucene.Net处理)。转换好的字符串Lucene.Net会把它的⽂本进⾏切词保存,加快检索速度。因为查询的时候先查询的分词,然后根据所出对应的分词搜索出对应的⽤户所要的内容。
Lucene.Net这样的优点:
①:效率⾼。
②:匹配程度⾼(可以嵌⼊分词的算法提⾼匹配程度)
什么是分词:
分词是核⼼算法,搜索引擎内部保存的就是⼀个个的词,⼀般英⽂的分词很容易,按照空格分隔就可以,在汉语中就⽐较⿇烦。⽐如:把中国位列世界前茅,通过分词就拆分为:中国,位列,世界,前茅,这四个词,拆分的词要和Lunece.Net进⾏匹配,然后出相关的内容。当然想那些⽆意义的词都不参与分词(⽐如:啊,the).
在Lunece.Net的不同的分词算法就是不同的类。所有的分词算法都是从Lucene.Net中继承,不同的分词算法有着不同的优点
⼀元分词:
在Lucene.Net 中有⼀个内置的分词算法,就是⼀元分词算法(StandardAnalyzer这个类)是将英⽂按照空格,标点符号等进⾏分词,将中⽂按照单个字进⾏分词,⼀个汉字算⼀个词,这种分词现在⼏乎是不⽤的。
⼆元分词:
⼆元分词算法,是每两个汉字算⼀个单词,⽹上的CJKAnalyzer这个类就是实现⼆元分词的。当然这个在现在的项⽬中也是⼏乎不⽤的。
基于词库的分词算法:
就是基于⼀个词库进⾏分词们可以提⾼分词的成功率,但是效率有点低。有庖丁解⽜,盘古分词等。
注意:⽬前没有三元分词的算法,继⼀元分词和⼆元分词就是词库算法。
以上就是分词的基本的概念以及各个分词的优缺点,下⾯开始进⼊代码实现
代码实现:
⼀元分词的代码实现:
/// <summary>
/// ⼀元分词
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
Analyzer analyer = new StandardAnalyzer();//创建⼀元分词的对象
TokenStream tokenStream = analyer.TokenStream("",new System.IO.StringReader("中国位列世界前茅"));            Lucene.Net.Analysis.Token token = null;
while ((token = tokenStream.Next()) != null)
{
Console.WriteLine(token.TermText());
}
}
效果截图:
⼆元分词代码实现:
⼆元分词和⼀元分词⼏乎⼀样就是new的实例不⼀样。⼆元分词的使⽤需要添加两个类
/// <summary>
/// ⼆元分词
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
Analyzer analyer = new CJKAnalyzer();//创建⼆元分词的对象
TokenStream tokenStream = analyer.TokenStream("", new System.IO.StringReader("河南,雄ci峙天东"));            Lucene.Net.Analysis.Token token = null;
while ((token = tokenStream.Next()) != null)
{
Console.WriteLine(token.TermText());
}
}
CJKAnalyzer 类:
using System.Collections;
using System.IO;
using Lucene.Net.Analysis;
namespace NSharp.SearchEngine.Lucene.Analysis.Cjk
{
public class CJKAnalyzer : Analyzer
{
public static string[] STOP_WORDS = {
"a", "and", "are", "as", "at", "be",
"but", "by", "for", "if", "in",
"into", "is", "it", "no", "not",
"of", "on", "or", "s", "such", "t",
"that", "the", "their", "then",
"there", "these", "they", "this",
"to", "was", "will", "with", "",
"www"
};
private Hashtable stopTable;
public CJKAnalyzer()
{
stopTable = StopFilter.MakeStopSet(STOP_WORDS);
}
public CJKAnalyzer(string[] stopWords)
{
stopTable = StopFilter.MakeStopSet(stopWords);
}
public override TokenStream TokenStream(string fieldName, TextReader reader)        {
TokenStream ts = new CJKTokenizer(reader);
return new StopFilter(ts, stopTable);
}
}
}
CJKTokenizer类:
using System;
using System.Collections;
using System.IO;
using Lucene.Net.Analysis;
namespace NSharp.SearchEngine.Lucene.Analysis.Cjk
{
public class CJKTokenizer:Tokenizer
{
private static int MAX_WORD_LEN = 255;
private static int IO_BUFFER_SIZE = 256;
private int offset = 0;
private int bufferIndex = 0;
private int dataLen = 0;
private char[] buffer = new char[MAX_WORD_LEN];
private char[] ioBuffer = new char[IO_BUFFER_SIZE];
private string tokenType = "word";
private bool preIsTokened = false;
public CJKTokenizer(TextReader reader)
{
{
input = reader;
}
public override Token Next()
{
int length = 0;
int start = offset;
while (true)
{
char c;
offset++;
if (bufferIndex >= dataLen )
{
if (dataLen==0 || dataLen>=ioBuffer.Length)//Java中read读到最后不会出错,但.Net会,所以此处是为了拦截异常                    {
dataLen = input.Read(ioBuffer,0,ioBuffer.Length);
bufferIndex = 0;
writeline方法属于类}
else
{
dataLen=0;
}
}
if (dataLen ==0)
{
if (length > 0)
{
if (preIsTokened == true)
{
length = 0;
preIsTokened = false;
}
break;
}
else
{
return null;
}
}
else
{
//get current character
c = ioBuffer[bufferIndex++];
}
if (IsAscii(c) || IsHALFWIDTH_AND_FULLWIDTH_FORMS(c))
{
if (IsHALFWIDTH_AND_FULLWIDTH_FORMS(c))
{
int i = (int) c;
i = i - 65248;
c = (char) i;
}
if (char.IsLetterOrDigit(c) || ((c == '_') || (c == '+') || (c == '#')))
{
if (length == 0)
{
start = offset - 1;
}
else if (tokenType == "double")
{
offset--;
bufferIndex--;
tokenType = "single";
if (preIsTokened == true)
{
length = 0;
preIsTokened = false;
break;
}
else
{
break;
}
}
buffer[length++] = char.ToLower(c);
tokenType = "single";
if (length == MAX_WORD_LEN)
{
break;
}
}
else if (length > 0)
{
if (preIsTokened == true)
{
length = 0;
preIsTokened = false;
}
else
{
break;
}
}
}
else
{
if (char.IsLetter(c))
{
if (length == 0)
{
start = offset - 1;
buffer[length++] = c;
tokenType = "double";
}
else
{
if (tokenType == "single")
{
offset--;
bufferIndex--;
//return the previous ASCII characters                                break;
}
else
{
buffer[length++] = c;
tokenType = "double";
if (length == 2)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。