找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 4032|回复: 1

站内搜索的实现

[复制链接]

33

主题

1

回帖

561

积分

用户组: 大·技术宅

UID
580
精华
26
威望
28 点
宅币
341 个
贡献
0 次
宅之契约
0 份
在线时间
8 小时
注册时间
2014-12-8
发表于 2015-1-24 10:55:09 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
基于Lucene.net3.03 加 ICTCLAS2014实现的站内搜索引擎

Lucene.net是一个搜索引擎的框架,它自身并不能实现搜索,需要我们自己在其中实现索引的建立,索引的查找。所有这些都是根据它自身提供的API来实现。Lucene.net本身是基于java的,但是经过翻译成.ne版本的,可以在ASP.net中使用这个来实现站内搜索。
    要实现基于汉语的搜索引擎,首先的要实现汉语的分词。目前网上大部分都是利用已经有的盘古分词来实现的分词系统,但是盘古分词效果不太好。在这里我把最新的ICTCLAS2014嵌入到Lucene.net中。Lucene.net中所有的分词系统都是基于Analyzer类来继承实现的。所以如果要使用ICTCLAS2014嵌入到Lucene.net中,就必要要继承Analyzer类实现自己的分词类。
1 ICTCLAS的引入
    首先我们要把ICTCLAS的dll引入到C#文件中 ,因为这个dll不是在C#中建立的类库,所以无法直接将其加入到C#的引用中。我们考虑使用下面的方法来实现,为了方便,我们把引入的函数以及结构体放入一个类中。如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Runtime.InteropServices;
  6. using Lucene.Net.Analysis;

  7. namespace Lucene.Net.Analysis.DChinese
  8. {
  9.     [StructLayout(LayoutKind.Explicit)]
  10.     public struct result_t
  11.     {
  12.         [FieldOffset(0)]
  13.         public int start;
  14.         [FieldOffset(4)]
  15.         public int length;
  16.         [FieldOffset(8)]
  17.         public int sPos1;
  18.         [FieldOffset(12)]
  19.         public int sPos2;
  20.         [FieldOffset(16)]
  21.         public int sPos3;
  22.         [FieldOffset(20)]
  23.         public int sPos4;
  24.         [FieldOffset(24)]
  25.         public int sPos5;
  26.         [FieldOffset(28)]
  27.         public int sPos6;
  28.         [FieldOffset(32)]
  29.         public int sPos7;
  30.         [FieldOffset(36)]
  31.         public int sPos8;
  32.         [FieldOffset(40)]
  33.         public int sPos9;
  34.         [FieldOffset(44)]
  35.         public int sPos10;
  36.         //[FieldOffset(12)] public int sPosLow;
  37.         [FieldOffset(48)]
  38.         public int POS_id;
  39.         [FieldOffset(52)]
  40.         public int word_ID;
  41.         [FieldOffset(56)]
  42.         public int word_type;
  43.         [FieldOffset(60)]
  44.         public double weight;
  45.     }
  46.     public class SplitWord
  47.     {
  48.         const string path = @"NLPIR.dll";//设定dll的路径

  49.         //对函数进行申明
  50.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_Init", CallingConvention = CallingConvention.Cdecl)]
  51.         public static extern bool NLPIR_Init(String sInitDirPath, int encoding = 0, String sLicenceCode = null);

  52.         //特别注意,C语言的函数NLPIR_API const char * NLPIR_ParagraphProcess(const char *sParagraph,int bPOStagged=1);必须对应下面的申明
  53.         [DllImport(path, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "NLPIR_ParagraphProcess")]
  54.         public static extern IntPtr NLPIR_ParagraphProcess(String sParagraph, int bPOStagged = 1);

  55.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_Exit", CallingConvention = CallingConvention.Cdecl)]
  56.         public static extern bool NLPIR_Exit();

  57.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_ImportUserDict", CallingConvention = CallingConvention.Cdecl)]
  58.         public static extern int NLPIR_ImportUserDict(String sFilename);

  59.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_FileProcess", CallingConvention = CallingConvention.Cdecl)]
  60.         public static extern bool NLPIR_FileProcess(String sSrcFilename, String sDestFilename, int bPOStagged = 1);

  61.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_FileProcessEx", CallingConvention = CallingConvention.Cdecl)]
  62.         public static extern bool NLPIR_FileProcessEx(String sSrcFilename, String sDestFilename);

  63.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_GetParagraphProcessAWordCount", CallingConvention = CallingConvention.Cdecl)]
  64.         public static extern int NLPIR_GetParagraphProcessAWordCount(String sParagraph);

  65.         //NLPIR_GetParagraphProcessAWordCount
  66.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_ParagraphProcessAW", CallingConvention = CallingConvention.Cdecl)]
  67.         public static extern void NLPIR_ParagraphProcessAW(int nCount, [Out, MarshalAs(UnmanagedType.LPArray)] result_t[] result);

  68.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_AddUserWord", CallingConvention = CallingConvention.Cdecl)]
  69.         public static extern int NLPIR_AddUserWord(String sWord);

  70.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_SaveTheUsrDic", CallingConvention = CallingConvention.Cdecl)]
  71.         public static extern int NLPIR_SaveTheUsrDic();

  72.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_DelUsrWord", CallingConvention = CallingConvention.Cdecl)]
  73.         public static extern int NLPIR_DelUsrWord(String sWord);

  74.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_NWI_Start", CallingConvention = CallingConvention.Cdecl)]
  75.         public static extern bool NLPIR_NWI_Start();

  76.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_NWI_Complete", CallingConvention = CallingConvention.Cdecl)]
  77.         public static extern bool NLPIR_NWI_Complete();

  78.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_NWI_AddFile", CallingConvention = CallingConvention.Cdecl)]
  79.         public static extern bool NLPIR_NWI_AddFile(String sText);

  80.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_NWI_AddMem", CallingConvention = CallingConvention.Cdecl)]
  81.         public static extern bool NLPIR_NWI_AddMem(String sText);

  82.         [DllImport(path, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "NLPIR_NWI_GetResult")]
  83.         public static extern IntPtr NLPIR_NWI_GetResult(bool bWeightOut = false);

  84.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_NWI_Result2UserDict", CallingConvention = CallingConvention.Cdecl)]
  85.         public static extern uint NLPIR_NWI_Result2UserDict();

  86.         [DllImport(path, CharSet = CharSet.Ansi, EntryPoint = "NLPIR_GetKeyWords", CallingConvention = CallingConvention.Cdecl)]
  87.         public static extern IntPtr NLPIR_GetKeyWords(String sText, int nMaxKeyLimit = 50, bool bWeightOut = false);

  88.         [DllImport(path, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "NLPIR_GetFileKeyWords")]
  89.         public static extern IntPtr NLPIR_GetFileKeyWords(String sFilename, int nMaxKeyLimit = 50, bool bWeightOut = false);
  90.     }
  91. }
复制代码
这个类里面包含了所有的ICTCLAS的API函数,包含初始化,添加词语,添加词典,词典保存,分词等各种API。并且都是STATIC函数。
2 分词类DChineseAnalyzer的建立
分词类的建立我们参考StandarAnalyzer分词的实现,再次基础上实现了DChineseAnalyzer类。在分词类中实现必要的构造函数,以及
  1. public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
  2. public override TokenStream ReusableTokenStream(System.String fieldName, System.IO.TextReader reader)
复制代码
这两个函数。他们的作用是在函数中调用用分词器Tokenizer的派生类来实现分词。在现有的版本中一般是在使用分词类的时候,直接调用ReusableTokenStream函数,而不是调用TokenStream函数,这样可以做到一个分词类对象的建立可供多个分词文本的使用。从而减少内存的浪费,提高效率。
以及一些字段,利用这些字段,我们可以加入一些停用词,用户自己的词典。
3 分词器DChineseTokenizer的建立
这个类是分词的核心关键所在。我们要在其中调用ICTCLAS中的分词。在这里面要注意的一个函数是
  1. public override bool IncrementToken()
复制代码
它是我们获取下一个分词结果要用到的函数,如果想要遍历分词结果,就要建立一个循环,不断的调用IncrementToken函数。
整个分词系统代码如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. using Lucene.Net.Analysis;
  8. using Lucene.Net.Analysis.Standard;
  9. using Lucene.Net.Util;
  10. using Lucene.Net.Documents;
  11. using Lucene.Net.Analysis.Tokenattributes;
  12. using Version = Lucene.Net.Util.Version;

  13. namespace Lucene.Net.Analysis.DChinese
  14. {
  15.     public class DChineseAnalyzer : Analyzer
  16.     {
  17.         private ISet<string> stopSet;
  18.         public static readonly ISet<string> STOP_WORDS_SET;
  19.         private Version matchVersion;
  20.         private bool replaceInvalidAcronym;
  21.         private bool enableStopPositionIncrements;

  22.         public DChineseAnalyzer(Version version, ISet<string> stopWords)
  23.         {
  24.             stopSet = stopWords;
  25.             replaceInvalidAcronym = false;
  26.             enableStopPositionIncrements = StopFilter.GetEnablePositionIncrementsVersionDefault(version);
  27.             replaceInvalidAcronym = matchVersion.OnOrAfter(Version.LUCENE_24);
  28.             this.matchVersion = version;
  29.         }

  30.         public DChineseAnalyzer(Version version)
  31.             : this(version, STOP_WORDS_SET)
  32.         {
  33.         }

  34.         public DChineseAnalyzer(Version version, System.IO.FileInfo stopWords)
  35.             : this(version, WordlistLoader.GetWordSet(stopWords))
  36.         {
  37.         }

  38.         static DChineseAnalyzer()
  39.         {
  40.             STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
  41.         }
  42.         public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
  43.         {
  44.             TokenStream result = new DChineseTokenizer(matchVersion, reader);
  45.             result = new LowerCaseFilter(result);
  46.             result = new StopFilter(enableStopPositionIncrements, result, stopSet);
  47.             result = new PorterStemFilter(result);
  48.             return result;
  49.         }

  50.         private class SavedStreams
  51.         {
  52.             protected internal DChineseTokenizer source;
  53.             protected internal TokenStream result;
  54.         };
  55.         public override TokenStream ReusableTokenStream(System.String fieldName, System.IO.TextReader reader)
  56.         {
  57.             SavedStreams streams = (SavedStreams)PreviousTokenStream;
  58.             if (streams == null)
  59.             {
  60.                 streams = new SavedStreams();
  61.                 streams.source = new DChineseTokenizer(matchVersion, reader);
  62.                 streams.result = new LowerCaseFilter(streams.source);
  63.                 streams.result = new StopFilter(enableStopPositionIncrements, streams.result, stopSet);
  64.                 streams.result = new PorterStemFilter(streams.result);
  65.                 PreviousTokenStream = streams;
  66.             }
  67.             else
  68.             {
  69.                 streams.source.Reset(reader);
  70.             }

  71.             streams.source.SetReplaceInvalidAcronym(replaceInvalidAcronym);
  72.             return streams.result;
  73.         }

  74.     }

  75.     public sealed class DChineseTokenizer : Tokenizer
  76.     {

  77.         private bool m_replaceInvalidAcronym;
  78.         private int offset = 0;
  79.         private int bufferIndex = 0;
  80.         private int dataLen = 0;
  81.         private const int MAX_WORD_LEN = 255;
  82.         private const int IO_BUFFER_SIZE = 4096;
  83.         private readonly char[] ioBuffer = new char[IO_BUFFER_SIZE];

  84.         private ITermAttribute termAtt;
  85.         private IOffsetAttribute offsetAtt;
  86.         private IPositionIncrementAttribute posIncrAtt;



  87.         private void Init(System.IO.TextReader input, Version matchVersion)
  88.         {
  89.             if (matchVersion.OnOrAfter(Version.LUCENE_24))
  90.             {
  91.                 m_replaceInvalidAcronym = true;
  92.             }
  93.             else
  94.             {
  95.                 m_replaceInvalidAcronym = false;
  96.             }
  97.             //this.input = input;
  98.             this.input = ChangeInput(input);
  99.             termAtt = AddAttribute<ITermAttribute>();
  100.             offsetAtt = AddAttribute<IOffsetAttribute>();
  101.             posIncrAtt = AddAttribute<IPositionIncrementAttribute>();
  102.         }

  103.         public DChineseTokenizer(Version matchVersion, System.IO.TextReader input)
  104.             : base()
  105.         {
  106.             Init(input, matchVersion);
  107.         }

  108.         public DChineseTokenizer(Version matchVersion, System.IO.TextReader input, AttributeSource source)
  109.             : base(source)
  110.         {
  111.             Init(input, matchVersion);
  112.         }

  113.         public DChineseTokenizer(Version matchVersion, System.IO.TextReader input, AttributeFactory factory)
  114.             : base(factory)
  115.         {
  116.             Init(input, matchVersion);
  117.         }

  118.         public override bool IncrementToken()
  119.         {
  120.             ClearAttributes();
  121.             int length = 0;
  122.             int start = bufferIndex;
  123.             char[] buffer = termAtt.TermBuffer();
  124.             while (true)
  125.             {

  126.                 if (bufferIndex >= dataLen)
  127.                 {
  128.                     offset += dataLen;
  129.                     dataLen = input.Read(ioBuffer, 0, ioBuffer.Length);
  130.                     if (dataLen <= 0)
  131.                     {
  132.                         dataLen = 0;
  133.                         if (length > 0)
  134.                             break;
  135.                         return false;
  136.                     }
  137.                     bufferIndex = 0;
  138.                 }

  139.                 char c = ioBuffer[bufferIndex++];

  140.                 if (!System.Char.IsWhiteSpace(c))
  141.                 {
  142.                     if (length == 0)
  143.                     {
  144.                         start = offset + bufferIndex - 1;
  145.                     }
  146.                     else if (length == buffer.Length)
  147.                     {
  148.                         buffer = termAtt.ResizeTermBuffer(1 + length);
  149.                     }

  150.                     buffer[length++] = c;
  151.                     if (length == MAX_WORD_LEN)
  152.                         break;
  153.                 }
  154.                 else if (length > 0)
  155.                     break;
  156.             }

  157.             termAtt.SetTermLength(length);
  158.             offsetAtt.SetOffset(CorrectOffset(start), CorrectOffset(start + length));
  159.             posIncrAtt.PositionIncrement = 1;
  160.             return true;
  161.         }

  162.         public override void Reset()
  163.         {
  164.             base.Reset(input);
  165.             bufferIndex = 0;
  166.             offset = 0;
  167.             dataLen = 0;
  168.         }

  169.         public override void Reset(TextReader input)
  170.         {
  171.             String inputString = input.ReadToEnd();
  172.             IntPtr intPtr = SplitWord.NLPIR_ParagraphProcess(inputString, 0);
  173.             string strResult = Marshal.PtrToStringAnsi(intPtr);
  174.             this.input = new StringReader(strResult);
  175.             bufferIndex = 0;
  176.             offset = 0;
  177.             dataLen = 0;
  178.         }

  179.         public override void End()
  180.         {
  181.             int finalOffset = CorrectOffset(offset);
  182.             offsetAtt.SetOffset(finalOffset, finalOffset);
  183.         }

  184.         public void SetReplaceInvalidAcronym(bool replaceInvalidAcronym)
  185.         {
  186.             this.m_replaceInvalidAcronym = replaceInvalidAcronym;
  187.         }

  188.         private TextReader ChangeInput(TextReader input)
  189.         {
  190.             //string indexPath = System.Environment.CurrentDirectory;
  191.             //string indexPath = GetType().Assembly.Location;
  192.             //string indexPath = System.IO.Path.GetDirectoryName(Page.Request.PhysicalPath);
  193.             //string dirParent = Directory.GetParent(indexPath).Parent.FullName;
  194.             string dirParent = System.AppDomain.CurrentDomain.BaseDirectory;
  195.             

  196.             bool bInit = SplitWord.NLPIR_Init(dirParent, 0, null);
  197.             if (!bInit)
  198.             {
  199.                 return null;
  200.             }
  201.             String inputString = input.ReadToEnd();
  202.             IntPtr intPtr = SplitWord.NLPIR_ParagraphProcess(inputString, 0);
  203.             string strResult = Marshal.PtrToStringAnsi(intPtr);
  204.             return new StringReader(strResult);
  205.         }
  206.     }
  207. }
复制代码
(2) 索引,查找
    分词系统建立完毕,这是基础也是核心,后面我们建立索引要用到分词系统。下面依次讲解索引的建立,索引的查找。
    索引的建立采用的是倒排序,原理就是遍历所有的文本,对其进行分词,然后把分的词汇建立索引表。形式类似如下:
词汇    出现词汇的篇章1,篇章2,篇章3……
    建立索引的时候要注意这样的Document,Field这俩术语。Document代表的是一个文档,它里面包含一个或者多个Filed,Field表示的就是一种域,你可以在一个Document里面添加各种各样的域,名字自己起,但是关于文档的内容一定要加进去,方式如下所示:
  1. doc.Add(new Field("contents", str, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
复制代码
整个索引的建立如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.IO;
  6. using Lucene.Net.Analysis;
  7. using Lucene.Net.Analysis.Standard;
  8. using Lucene.Net.Index;
  9. using Lucene.Net.Documents;
  10. using Lucene.Net.Search;
  11. using Lucene.Net.Analysis.DChinese;

  12. using Version = Lucene.Net.Util.Version;
  13. using FSDirectory = Lucene.Net.Store.FSDirectory;
  14. using NativeFSLockFactory = Lucene.Net.Store.NativeFSLockFactory;

  15. namespace WebApplication6
  16. {
  17.     public class IndexFiles
  18.     {
  19.         

  20.         public static bool CreateIndexFromFile(DirectoryInfo docDir, DirectoryInfo IndexDir)
  21.         {
  22.             string strUserDicPath = System.AppDomain.CurrentDomain.BaseDirectory;
  23.             string strTestDic = strUserDicPath;
  24.             HashSet<string> lstStopWords = new HashSet<string>();

  25.             strUserDicPath = strUserDicPath + "UserDictionary\\StopWords.txt";
  26.             string[] strs = null;

  27.             StreamWriter sw = new StreamWriter(strTestDic + "UserDictionary\\StopTest.txt");
  28.             using (StreamReader strReader = new StreamReader(strUserDicPath))
  29.             {
  30.                 string strLine;
  31.                 while ((strLine = strReader.ReadLine()) != null)
  32.                 {
  33.                     strLine = strLine.Trim();
  34.                     strs = strLine.Split();
  35.                     foreach (string str in strs)
  36.                     {
  37.                         lstStopWords.Add(str);
  38.                         sw.WriteLine(str);
  39.                         
  40.                     }
  41.                 }
  42.                 strReader.Close();
  43.                 sw.Close();
  44.             }

  45.             bool bExist = File.Exists(docDir.FullName) || Directory.Exists(docDir.FullName);
  46.             if (!bExist)
  47.             {
  48.                 return false;
  49.             }

  50.             //using (IndexWriter writer = new IndexWriter(FSDirectory.Open(IndexDir), new DChineseAnalyzer(Version.LUCENE_30), true, IndexWriter.MaxFieldLength.LIMITED) )
  51.             //IndexWriter writer = new IndexWriter(fsDirrctory, new StandardAnalyzer(Version.LUCENE_30), true, IndexWriter.MaxFieldLength.LIMITED);
  52.             
  53.             FSDirectory fsDirrctory = FSDirectory.Open(IndexDir, new NativeFSLockFactory());
  54.             Analyzer analyzer = new DChineseAnalyzer(Version.LUCENE_30,lstStopWords);
  55.             IndexWriter writer = new IndexWriter(fsDirrctory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
  56.             try
  57.             {
  58.                 IndexDirectory(writer, docDir);
  59.                 writer.Optimize();
  60.                 writer.Commit();
  61.             }
  62.             finally
  63.             {
  64.                 writer.Dispose();
  65.                 fsDirrctory.Dispose();
  66.             }
  67.             
  68.             return true;
  69.         }

  70.         internal static void IndexDirectory(IndexWriter writer, DirectoryInfo directory)
  71.         {
  72.             foreach (var subDirectory in directory.GetDirectories())
  73.                 IndexDirectory(writer, subDirectory);

  74.             foreach (var file in directory.GetFiles())
  75.                 IndexDocs(writer, file);
  76.         }

  77.         internal static void IndexDocs(IndexWriter writer, FileInfo file)
  78.         {
  79.             Console.Out.WriteLine("adding " + file);

  80.             try
  81.             {
  82.                 writer.AddDocument(Document(file));
  83.             }
  84.             catch (FileNotFoundException)
  85.             {
  86.                 // At least on Windows, some temporary files raise this exception with an
  87.                 // "access denied" message checking if the file can be read doesn't help.
  88.             }
  89.             catch (UnauthorizedAccessException)
  90.             {
  91.                 // Handle any access-denied errors that occur while reading the file.   
  92.             }
  93.             catch (IOException)
  94.             {
  95.                 // Generic handler for any io-related exceptions that occur.
  96.             }
  97.         }

  98.         public static Document Document(FileInfo f)
  99.         {

  100.             // make a new, empty document
  101.             Document doc = new Document();

  102.             // Add the path of the file as a field named "path".  Use a field that is
  103.             // indexed (i.e. searchable), but don't tokenize the field into words.
  104.             doc.Add(new Field("path", f.FullName, Field.Store.YES, Field.Index.NOT_ANALYZED));

  105.             // Add the last modified date of the file a field named "modified".  Use
  106.             // a field that is indexed (i.e. searchable), but don't tokenize the field
  107.             // into words.
  108.             doc.Add(new Field("modified", DateTools.TimeToString(f.LastWriteTime.Millisecond, DateTools.Resolution.MINUTE), Field.Store.YES, Field.Index.NOT_ANALYZED));

  109.             // Add the contents of the file to a field named "contents".  Specify a Reader,
  110.             // so that the text of the file is tokenized and indexed, but not stored.
  111.             // Note that FileReader expects the file to be in the system's default encoding.
  112.             // If that's not the case searching for special characters will fail.

  113.             string str = File.ReadAllText(f.FullName);
  114.             //doc.Add(new Field("contents", new StreamReader(f.FullName, System.Text.Encoding.UTF8)));
  115.             doc.Add(new Field("contents", str, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));

  116.             // return the document
  117.             return doc;
  118.         }
  119.     }
  120. }
复制代码
查找的实现:
    Lucene.net中有多种多样的查找类,但是如果要实现多条件查询就要使用PhraseQuery
类。通过搜索函数把搜索结果放到容器里面。
    最后结果的呈现时候,我们把搜索结果放到列表里面,如果还要显示关键词加亮,那么就需要做一点额外的工作。在这里我是通过ColorWord这个类实现的。具体的搜索代码如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.IO;
  6. using Lucene.Net.Analysis;
  7. using Lucene.Net.Analysis.DChinese;
  8. using Lucene.Net.Documents;
  9. using Lucene.Net.QueryParsers;
  10. using Lucene.Net.Index;
  11. using Lucene.Net.Search;

  12. using FSDirectory = Lucene.Net.Store.FSDirectory;
  13. using NoLockFactory = Lucene.Net.Store.NoLockFactory;
  14. using Version = Lucene.Net.Util.Version;

  15. namespace WebApplication6
  16. {
  17.     public static class SearchFiles
  18.     {
  19.         public static List<ItemList> SearchIndex(DirectoryInfo dirIndex, List<string> termList)
  20.         {
  21.             FSDirectory     dirFS    = FSDirectory.Open(dirIndex, new NoLockFactory());
  22.             IndexReader     reader   = IndexReader.Open(dirFS,true);
  23.             IndexSearcher   searcher = new IndexSearcher(reader);
  24.             Analyzer        analyzer = new DChineseAnalyzer(Version.LUCENE_30);
  25.             PhraseQuery     query    = new PhraseQuery();

  26.             foreach (string word in termList)
  27.             {
  28.                 query.Add( new Term("contents",word) );
  29.             }
  30.             query.Slop = 100;

  31.             TopScoreDocCollector collector = TopScoreDocCollector.Create(1000, true);
  32.             searcher.Search(query,collector);
  33.             ScoreDoc[] hits = collector.TopDocs().ScoreDocs;
  34.             List<ItemList> lstResult = new List<ItemList>();
  35.             for (int i = 0; i < hits.Length; i++)
  36.             {
  37.                 Document doc = new Document();
  38.                 doc = searcher.Doc(hits[i].Doc);
  39.                 ItemList item = new ItemList();
  40.                 //item.ItemContent = doc.Get("contents");
  41.                 item.ItemContent = ColorWord.addColor(doc.Get("contents"),termList);
  42.                 item.ItemPath = doc.Get("path");
  43.                 lstResult.Add(item);
  44.             }
  45.             return lstResult;
  46.         }
  47.     }
  48. }
复制代码
最终结果展示:
1.png
回复

使用道具 举报

1110

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24221 个
贡献
46222 次
宅之契约
0 份
在线时间
2296 小时
注册时间
2014-1-26
发表于 2015-1-24 10:56:03 | 显示全部楼层
你能把它改成PHP的吗?我论坛是PHP的,正缺这么一个搜索引擎呢。
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-19 06:42 , Processed in 0.042139 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表