首页 »编程综合 » lucene分词:Lucene.Net 2.3.1开发介绍 2、分词( 5) »正文
lucene分词:Lucene.Net 2.3.1开发介绍 2、分词( 5)
来源: 发布时间:星期四, 2009年1月15日 浏览:2次 评论:0
2.1.3 2元分词 上 节通过变换查询表达式满足了需求 但是在实际应用中 如果那样查询 会出现另外 个问题 那样搜索 是只要出现这个字 不管它出现在什么位置 这就产生了上 小节开头讲 对准确性产生了极大干扰 比如 如果有 段这样 话:“这是 个英雄!他有无法用词汇形容 孤单 但是他并没有用言语来表达 ”这句话包含了“英 语 单 词”这 4个字 但是却和“英语单词” 点关系都没有 首先想到 解决思路方法 就是把句子按词来划分 那么就能有效 降低干扰 最简单 解决思路方法 莫过于每两个字组成 个部分 下面来构造核心算法 首先我们期望 只有中文(广义上指双字节文字 比如日文 韩文也在这个范围 )是按照 2元拆分 而符号则是单符号拆分 对于英文则保持原样 因此 需要 个判断当前 类型 首先 构造 个枚举 如代码2.1.3.1 代码 2.1.3.1 Code /// <summary> /// Char类型枚举用于分词中类型状态比较 /// </summary> public enum CharType { None, //默认值不可识别类型 English, //拉丁用英文标识 Chinese, //CJK以中文代表 Number, //阿拉伯数字 Control //控制符号指控制符号已经各种标点符号等 } 接下来需要有 个 能够识别 把 类型转换成我们需要 CharType 代码 2.1.3.2 Code 1/**//// <summary> 2/// 获取Char类型 3/// </summary> 4/// <param name="c"></param> 5/// <s>返回类型</s> 6public CharType GetCharType(char c) 7{ 8 switch (char.GetUnicodeCategory(c)) 9 { 10 //大小写判断为英文 11 .Globalization.UnicodeCategory.UpperLetter: 12 .Globalization.UnicodeCategory.LowerLetter: 13 CharType.English; 14 //其它判断问中文(CJK) 15 .Globalization.UnicodeCategory.OtherLetter: 16 CharType.Chinese; 17 //十进制数字 18 .Globalization.UnicodeCategory.DecimalDigitNumber: 19 CharType.Number; 20 //其他都认为是符号 21 default: 22 CharType.Control; 23 } 24}
代码2.1.3.2粗略完成了我们想要 功能 现在就可以构造我们想要 算法了 代码 2.1.3.3 Code 1using ; 2using .Collections.Generic; 3using .Text; 4using Lucene.Net.Analysis; 5using .IO; 6 7 Test.Analysis 8{ 9 public DoubleTokenizer : Tokenizer 10 { 11 /**//// <summary> 12 /// 保持传入流 13 /// </summary> 14 private TextReader reader; 15 /**//// <summary> 16 /// 控制分词器只打开次 17 /// </summary> 18 private bool done = true; 19 /**//// <summary> 20 /// 保存分词结果 21 /// </summary> 22 private List<Token> tokenlist; 23 24 public DoubleTokenizer(TextReader reader) 25 { 26 this.reader = reader; 27 } 28 /**//// <summary> 29 /// 上个字类型 30 /// </summary> 31 private CharType lastype = CharType.None; 32 /**//// <summary> 33 /// 当前读取到分词记录数 34 /// </summary> 35 private ptr = 0; 36 /**//// <summary> 37 /// 重写Next思路方法 38 /// </summary> 39 /// <param name="result"></param> 40 /// <s></s> 41 public override Token Next(Token result) 42 { 43 (done) //第次可以运行运行后将被设置为false,在个例子中只会运行次 44 { 45 done = false; 46 text = reader.ReadToEnd; 47 //输入为空则返回结束符号 48 (.IsNullOrEmpty(text)) 49 null; 50 //化分词结果 51 tokenlist = List<Token>; 52 //缓冲器主要用于暂时保存英文数字 53 StringBuilder buffer = StringBuilder; 54 Token token; 55 for ( i = 0; i < text.Length; i) 56 { 57 char nowchar = text[i]; 58 char nextchar = char; 59 CharType nowtype = GetCharType(nowchar); 60 (i < text.Length - 1) //取下个 61 nextchar = text[i + 1]; 62 //状态转换 63 (nowtype != lastype) 64 { 65 lastype = nowtype; 66 (buffer.Length > 0) 67 { 68 token = Token(buffer., i - buffer.Length, i); 69 tokenlist.Add(token); 70 buffer.Remove(0, buffer.Length); 71 } 72 } 73 74 switch (nowtype) 75 { 76 CharType.None: 77 CharType.Control: 78 goto SingleChar; 79 CharType.Chinese: 80 ; 81 CharType.English: 82 CharType.Number: 83 buffer.Append(nowchar); 84 continue; 85 } 86 //处理连续两个中文 87 (GetCharType(nextchar) CharType.Chinese) 88 { 89 token = Token(nowchar. + nextchar., i, i + 2); 90 tokenlist.Add(token); 91 i; 92 continue; 93 } 94 95 SingleChar: //处理单个 96 token = Token(nowchar., i, i + 1); 97 tokenlist.Add(token); 98 continue; 99 } 100 //返回第个分词结果并且把指针移向下位 101 tokenlist[ptr]; 102 } 103 104 { 105 //在分词结果范围内取词 106 (ptr < tokenlist.Count) 107 tokenlist[ptr]; 108 //超出则返回结束符号 109 null; 110 } 111 } 112 /**//// <summary> 113 /// 获取Char类型 114 /// </summary> 115 /// <param name="c"></param> 116 /// <s>返回类型</s> 117 public CharType GetCharType(char c) 118 { 119 switch (char.GetUnicodeCategory(c)) 120 { 121 //大小写判断为英文 122 .Globalization.UnicodeCategory.UpperLetter: 123 .Globalization.UnicodeCategory.LowerLetter: 124 CharType.English; 125 //其它判断问中文(CJK) 126 .Globalization.UnicodeCategory.OtherLetter: 127 CharType.Chinese; 128 //十进制数字 129 .Globalization.UnicodeCategory.DecimalDigitNumber: 130 CharType.Number; 131 //其他都认为是符号 132 default: 133 CharType.Control; 134 } 135 } 136 } 137 /**//// <summary> 138 /// Char类型枚举用于分词中类型状态比较 139 /// </summary> 140 public enum CharType 141 { 142 None, //默认值不可识别类型 143 English, //拉丁用英文标识 144 Chinese, //CJK以中文代表 145 Number, //阿拉伯数字 146 Control //控制符号指控制符号已经各种标点符号等 147 } 148 149}
代码2.1.3.3就是构造完后 算法 意思就是把英文字母 数字按空格或者符号划分 而中文则 2元拆分 现在来测试下效果 代码 2.1.3.4 Code 1using ; 2using .Collections.Generic; 3using .Text; 4using NUnit.Framework; 5using .IO; 6using Lucene.Net.Analysis; 7 8 Test.Analysis 9{ 10 [TestFixture] 11 public DoubleTokenizerTest 12 { 13 [Test] 14 public void NextTest 15 { 16 testwords = "我是个中国人代码yurow001,真是个好名字啊!!!哈哈哈"; 17 DoubleTokenizer tk = DoubleTokenizer( StringReader(testwords)); 18 Token token; 19 while ((token = tk.Next) != null) 20 { 21 Console.WriteLine(token.TermText + "t" + token.StartOff + "t" + token.EndOff); 22 } 23 tk.Close; 24 } 25 } 26} 27 代码 2.1.3.4 就是测试代码 测试 输入包含了各种 来看 下效果 测试结果: 我是 0 2 个 2 4 中国 4 6 人 6 7 7 8 代码 8 10 yurow 10 15 001 15 18 , 18 19 真是 19 21 个好 21 23 名字 23 25 啊 25 26 ! 26 27 ! 27 28 ! 28 29 哈哈 29 31 哈 31 32 32 33 33 34 34 35
应该说结果符合我们 预期 下来写个Analyzer包装 并把这个包装应用到上 节2.1.2 方案里去 代码 2.1.3.5 Code 1using ; 2using .Collections.Generic; 3using .Text; 4using Lucene.Net.Analysis; 5 6 Test.Analysis 7{ 8 public DoubleAnalyzer : Analyzer 9 { 10 public override TokenStream TokenStream( fieldName, .IO.TextReader reader) 11 { 12 DoubleTokenizer(reader); 13 } 14 } 15} 16 代码2.1.3.5就是包装 结果 测试结果: 搜索词:英语 结果: content:英语 ----------------------------------- 搜索词:语法 结果: content:语法 ----------------------------------- 搜索词:单词 结果: content:单词 ----------------------------------- 搜索词:口语 结果: content:口语 ----------------------------------- 搜索词:+content:"英" +content:"语" +content:"单" +content:"词" 结果: +content:英 +content:语 +content:单 +content:词 ----------------------------------- What's happened? 为什么没有结果?分词器写错了?不要灰心!让我们来分析 下 在DoubleTokenizer类构造 下 个断点 调试 如果能正确运行 这个构造 肯定要进入 调试后看到了什么?传入 TextReader 类型是Lucene.Net.Index.DocumentsWriter.ReusableStringReader 查看Lucene.Net.Index.DocumentsWriter.ReusableStringReader类 定义 它继承自StringReader类 但是它重写掉了 些思路方法 而且 我们并没有发现我们使用 ReadToEnd思路方法 问题可能出在这里 看到ReusableStringReader类重写 Read(char , , )思路方法 试试这个
代码 2.1.3.6 Code 1using ; 2using .Collections.Generic; 3using .Text; 4using Lucene.Net.Analysis; 5using .IO; 6 7 Test.Analysis 8{ 9 public DoubleTokenizer : Tokenizer 10 { 11 /**//// <summary> 12 /// 保持传入流 13 /// </summary> 14 //private TextReader reader; 15 /**//// <summary> 16 /// 控制分词器只打开次 17 /// </summary> 18 private bool done = true; 19 /**//// <summary> 20 /// 保存分词结果 21 /// </summary> 22 private List<Token> tokenlist; 23 24 public DoubleTokenizer(TextReader reader) 25 { 26 this.input = reader; 27 } 28 /**//// <summary> 29 /// 上个字类型 30 /// </summary> 31 private CharType lastype = CharType.None; 32 /**//// <summary> 33 /// 当前读取到分词记录数 34 /// </summary> 35 private ptr = 0; 36 /**//// <summary> 37 /// 重写Next思路方法 38 /// </summary> 39 /// <param name="result"></param> 40 /// <s></s> 41 public override Token Next(Token result) 42 { 43 (done) //第次可以运行运行后将被设置为false,在个例子中只会运行次 44 { 45 done = false; 46 47 //------------------------------------------------------- 48 //使用传入参数作为缓冲区 49 char charbuffer = result.TermBuffer; 50 upto = 0; 51 result.Clear; 52 while (true) 53 { 54 length = input.Read(charbuffer, upto, charbuffer.Length - upto); 55 (length <= 0) 56 ; 57 upto length; 58 (upto charbuffer.Length) 59 charbuffer = result.ResizeTermBuffer(1 + charbuffer.Length); 60 } 61 result.SetTermLength(upto); 62 //------------------------------------------------------ 63 text = result.TermText; 64 //输入为空则返回结束符号 65 (.IsNullOrEmpty(text)) 66 null; 67 //化分词结果 68 tokenlist = List<Token>; 69 //缓冲器主要用于暂时保存英文数字 70 StringBuilder buffer = StringBuilder; 71 Token token; 72 for ( i = 0; i < text.Length; i) 73 { 74 char nowchar = text[i]; 75 char nextchar = char; 76 CharType nowtype = GetCharType(nowchar); 77 (i < text.Length - 1) //取下个 78 nextchar = text[i + 1]; 79 //状态转换 80 (nowtype != lastype) 81 { 82 lastype = nowtype; 83 (buffer.Length > 0) 84 { 85 token = Token(buffer., i - buffer.Length, i); 86 tokenlist.Add(token); 87 buffer.Remove(0, buffer.Length); 88 } 89 } 90 91 switch (nowtype) 92 { 93 CharType.None: 94 CharType.Control: 95 goto SingleChar; 96 CharType.Chinese: 97 ; 98 CharType.English: 99 CharType.Number: 100 buffer.Append(nowchar); 101 continue; 102 } 103 //处理连续两个中文 104 (GetCharType(nextchar) CharType.Chinese) 105 { 106 token = Token(nowchar. + nextchar., i, i + 2); 107 tokenlist.Add(token); 108 i; 109 continue; 110 } 111 112 SingleChar: //处理单个 113 token = Token(nowchar., i, i + 1); 114 tokenlist.Add(token); 115 continue; 116 } 117 //返回第个分词结果并且把指针移向下位 118 tokenlist[ptr]; 119 } 120 121 { 122 //在分词结果范围内取词 123 124 (ptr < tokenlist.Count) 125 { 126 tokenlist[ptr]; 127 } 128 //超出则返回结束符号 129 null; 130 } 131 } 132 /**//// <summary> 133 /// 获取Char类型 134 /// </summary> 135 /// <param name="c"></param> 136 /// <s>返回类型</s> 137 public CharType GetCharType(char c) 138 { 139 switch (char.GetUnicodeCategory(c)) 140 { 141 //大小写判断为英文 142 .Globalization.UnicodeCategory.UpperLetter: 143 .Globalization.UnicodeCategory.LowerLetter: 144 CharType.English; 145 //其它判断问中文(CJK) 146 .Globalization.UnicodeCategory.OtherLetter: 147 CharType.Chinese; 148 //十进制数字 149 .Globalization.UnicodeCategory.DecimalDigitNumber: 150 CharType.Number; 151 //其他都认为是符号 152 default: 153 CharType.Control; 154 } 155 } 156 } 157 /**//// <summary> 158 /// Char类型枚举用于分词中类型状态比较 159 /// </summary> 160 public enum CharType 161 { 162 None, //默认值不可识别类型 163 English, //拉丁用英文标识 164 Chinese, //CJK以中文代表 165 Number, //阿拉伯数字 166 Control //控制符号指控制符号已经各种标点符号等 167 } 168 169} 170 代码改造成了2.1.3.6 主要 改变在于用父类 input字段保持了读入流 然后用Token作为缓冲区 它实现了可变缓冲区 简化了我们 开发 测试结果 搜索词:英语 结果: content:英语 英语单词 语法 口语都很重要 口语 语法 单词都是英语 重要组成部分 ----------------------------------- 搜索词:语法 结果: content:语法 英语单词 语法 口语都很重要 口语 语法 单词都是英语 重要组成部分 ----------------------------------- 搜索词:单词 结果: content:单词 英语单词 语法 口语都很重要 口语 语法 单词都是英语 重要组成部分 我们要学好英语不但要学语法 单词还有口语 ----------------------------------- 搜索词:口语 结果: content:口语 英语单词 语法 口语都很重要 口语 语法 单词都是英语 重要组成部分 我们要学好英语不但要学语法 单词还有口语 ----------------------------------- 搜索词:+content:"英" +content:"语" +content:"单" +content:"词" 结果: +content:英 +content:语 +content:单 +content:词 ----------------------------------- 终于OK了!!!呵呵
相关文章
读者评论
发表评论
|
|