专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »编程综合 » 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了!!!呵呵



相关文章

读者评论

  • 共0条 分0页

发表评论

  • 昵称:
  • 内容: