且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

更新时间:2022-10-08 13:06:50

原文:Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来。目前Lucene.Net的分词库很不完善,实际应用价值不高。唯一能用在实际场合的StandardAnalyzer类,效果也不是很好。内置在Lucene.Net里的分词都被放在项目的Analysis目录下,也就是Lucene.Net.Analysis命名空间下。分词类的命名一般都是以“Analyzer”结束,比如StandardAnalyzerStopAnalyzer,SimpleAnalyzer等。全部继承自Analyzer类。而它们一般各有一个辅助类,一般以”“Tokenizer”结尾,分词的逻辑大都在辅助类完成。

使用Lucene.Net,要很好地使用Lucene.Net,必须理解分词,甚至能自己扩展分词。如果只使用拉丁语系,那么使用内置的分词可能足够了,但是对于中文肯定是不行的。目前中文方面的分词分为单字分词,二元分词,词库匹配,语义理解这几种。StandardAnalyzer类就是按单字分,二元分就是把两个字作为一组拆分,而词库的话肯定是有一个复杂的对比过程,语义理解的就更加复杂了。这是分词的方式,而匹配的方式也分为正向和逆向两种,一般逆向要优于正向,但是写起来也要复杂一些。

 

1、内置分词器

本节将详细介绍Lucene.Net内置分词的效果,工作过程,及整体结构。

 

1.1、分词效果

 

1.1.1 如果得到分词效果

如果得到分词效果?有效的方式就是进行测试。这里将引入自动测试的方法,这样更加便于测试,将使用NUnit来完成。Nunit的简单实用方法见附录二。

创建一个新的项目,命名为Test。步骤如图 1.1.1.1 - 1.1.1.2

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

图1.1.1.1

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

图 1.1.1.2

 

点确定,就加入了新项目Test,选择类库模板。再引用Nunit.framework类库。如图 1.1.1.3。

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

图 1.1.1.3

 

再按第一章节的步骤引入Lucene.Net类库。先来试试SimpleAnalyzer类的效果。在Test项目中添加SimpleAnalyzerTest,代码 1.1.1.1

 

代码 1.1.1.1

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Code
 1Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System;
 2Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Collections.Generic;
 3Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Text;
 4Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using NUnit.Framework;
 5Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using Lucene.Net.Analysis;
 6Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.IO;
 7Lucene.Net 2.3.1开发介绍 —— 二、分词(一)namespace Test
 8Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
 9Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    [TestFixture]
10Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    public class SimpleAnalyzerTest
11Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
12Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        [Test]
13Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        public void ReusableTokenStreamTest()
14Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
15Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            string testwords = "我是中国人,I can speak chinese!";
16Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
17Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            SimpleAnalyzer simple = new SimpleAnalyzer();
18Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            TokenStream ts = simple.ReusableTokenStream(""new StringReader(testwords));
19Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            Token token;
20Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            while ((token = ts.Next()) != null)
21Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
22Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                Console.WriteLine(token.TermText());
23Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            }

24Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            ts.Close();
25Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        }

26Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    }

27Lucene.Net 2.3.1开发介绍 —— 二、分词(一)}

28Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

 

运行结果:

 

我是中国人
i
can
speak
chinese

查看这个结果,基本可以确定,SimpleAnalyzer分词就是以空格或符号为断点,把句子分析出来。对于英文大写还会执行一个转换到小写的操作。

 

1.1.2 内置分词的分词效果

按照1.1.1节介绍的方式,就可以分析分析效果了。不过这样写出来的测试代码过于麻烦,改造一下。

(1)、在Test项目中新建Analysis目录;

(2)、在Analysis下建立TestData类,代码1.1.2.1;

 

代码1.1.2.1

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Code
 1Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System;
 2Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Collections.Generic;
 3Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Text;
 4Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
 5Lucene.Net 2.3.1开发介绍 —— 二、分词(一)namespace Test.Analysis
 6Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
 7Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    public class TestData
 8Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
 9Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        public static string TestWords = "我是中国人,I can speak chinese!";
10Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    }

11Lucene.Net 2.3.1开发介绍 —— 二、分词(一)}

12Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

 

(3)、建立TestFactory类,代码1.1.2.2

 

代码1.1.2.2

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Code
 1Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System;
 2Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Collections.Generic;
 3Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Text;
 4Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using Lucene.Net.Analysis;
 5Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.IO;
 6Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
 7Lucene.Net 2.3.1开发介绍 —— 二、分词(一)namespace Test.Analysis
 8Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
 9Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    public class TestFactory
10Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
11Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        public static void TestFunc(Analyzer analyzer)
12Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
13Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            TokenStream ts = analyzer.ReusableTokenStream(""new StringReader(TestData.TestWords));
14Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            Token token;
15Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            while ((token = ts.Next()) != null)
16Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
17Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                Console.WriteLine(token.TermText());
18Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            }

19Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            ts.Close();
20Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        }

21Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    }

22Lucene.Net 2.3.1开发介绍 —— 二、分词(一)}

 

(4)、建立AllAnalysisTest类,代码1.1.2.3

 

代码1.1.2.3

 

Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Code
 1Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System;
 2Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Collections.Generic;
 3Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using System.Text;
 4Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using NUnit.Framework;
 5Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using Lucene.Net.Analysis;
 6Lucene.Net 2.3.1开发介绍 —— 二、分词(一)using Lucene.Net.Analysis.Standard;
 7Lucene.Net 2.3.1开发介绍 —— 二、分词(一)namespace Test.Analysis
 8Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
 9Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    [TestFixture]
10Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    public class AllAnalysisTest
11Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
12Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        [Test]
13Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        public void TestMethod()
14Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
15Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            List<Analyzer> analysis = new List<Analyzer>() Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
16Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                new KeywordAnalyzer(),
17Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                new SimpleAnalyzer(),
18Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                new StandardAnalyzer(),
19Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                new StopAnalyzer(),
20Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                new WhitespaceAnalyzer() }
;
21Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
22Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            for (int i = 0; i < analysis.Count; i++)
23Lucene.Net 2.3.1开发介绍 —— 二、分词(一)Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            Lucene.Net 2.3.1开发介绍 —— 二、分词(一){
24Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                Console.WriteLine(analysis[i].ToString() + "结果:");
25Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                Console.WriteLine("--------------------------------");
26Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                TestFactory.TestFunc(analysis[i]);
27Lucene.Net 2.3.1开发介绍 —— 二、分词(一)                Console.WriteLine("--------------------------------");
28Lucene.Net 2.3.1开发介绍 —— 二、分词(一)            }

29Lucene.Net 2.3.1开发介绍 —— 二、分词(一)        }

30Lucene.Net 2.3.1开发介绍 —— 二、分词(一)    }

31Lucene.Net 2.3.1开发介绍 —— 二、分词(一)}

32Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

 

(5)、运行。

 

对于TestWords = "我是中国人,I can speak chinese!";测试结果:

 

Lucene.Net.Analysis.KeywordAnalyzer结果:
--------------------------------
我是中国人,I can speak chinese!
--------------------------------
Lucene.Net.Analysis.SimpleAnalyzer结果:
--------------------------------
我是中国人
i
can
speak
chinese
--------------------------------
Lucene.Net.Analysis.Standard.StandardAnalyzer结果:
--------------------------------





i
can
speak
chinese
--------------------------------
Lucene.Net.Analysis.StopAnalyzer结果:
--------------------------------
我是中国人
i
can
speak
chinese
--------------------------------
Lucene.Net.Analysis.WhitespaceAnalyzer结果:
--------------------------------
我是中国人,I
can
speak
chinese!
--------------------------------

 

换一句话试试:更改TestDataTestWords字段值为“我是中国人,I'can speak chinese,hello world,沪江小Q!”。测试结果:

 

Lucene.Net.Analysis.KeywordAnalyzer结果:
--------------------------------
我是中国人,I'can speak chinese,hello world,沪江小Q!
--------------------------------
Lucene.Net.Analysis.SimpleAnalyzer结果:
--------------------------------
我是中国人
i
can
speak
chinese
hello
world
沪江小q
--------------------------------
Lucene.Net.Analysis.Standard.StandardAnalyzer结果:
--------------------------------





i'can
speak
chinese



q
--------------------------------
Lucene.Net.Analysis.StopAnalyzer结果:
--------------------------------
我是中国人
i
can
speak
chinese
hello
world
沪江小q
--------------------------------
Lucene.Net.Analysis.WhitespaceAnalyzer结果:
--------------------------------
我是中国人,I'can
speak
chinese,hello
world,沪江小Q!
--------------------------------

 对于这几种分词效果基本可以看出来了。

KeywordAnalyzer分词,没有任何变化;

SimpleAnalyzer对中文效果太差;

StandardAnalyzer对中文单字拆分;

StopAnalyzerSimpleAnalyzer差不多;

WhitespaceAnalyzer只按空格划分。

 

当然,这只是个粗略的结果。