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

2.1.2 可以使用的内置分词

 

简单的分词方式并不能满足需求。前文说过Lucene.Net内置分词中StandardAnalyzer分词还算比较实用(见1.1.2小节)。StandardAnalyzer为什么能满足我们的部分需求,而它又有哪些不足呢?看分词的好坏还是要从效果说起。简单的说,在中英文混合的情况下,StandardAnalyzer会把英文按空格拆,而中文则按单字拆。因为中文是按单字拆,所以对分词的准确性起到了干扰,搜索结果就会不准确,至少理论上是这样的。但是实际上StandardAnalyzer分词器并没有我们想的那么差劲。因为搜索不光与分词有关,还和查询的逻辑有关,这个会在第四章讲搜索的时候讲。作为其中的一个重要要素的,可以说是基础的分词器,当然还是扮演了很关键的角色,查询的逻辑是以分词为基础的。分词是原石,而查询逻辑则能对它雕琢。

 

事实上如果没有用过StandardAnalyzer分词器,没有用它来解决一些问题,并且找到有哪些地方不足,那并不能弄清楚你要什么样的分词器。比如,现在有一些内容,用StandardAnalyzer作为分词器已经建立好了索引,接下来,进行查询操作。

 

 

代码 2.1.2.1

 


 1using System;
 2using Lucene.Net.Analysis;
 3using Lucene.Net.Analysis.Standard;
 4using Lucene.Net.Documents;
 5using Lucene.Net.Index;
 6using Lucene.Net.QueryParsers;
 7using Lucene.Net.Search;
 8using NUnit.Framework;
 9using System.Collections.Generic;
10
11namespace Test
12{
13    [TestFixture]
14    public class StandardAnalyzerCaseTest
15    {
16        /// <summary>
17        /// 执行测试的入口
18        /// </summary>
19        [Test]
20        public void SearcherTest()
21        {
22            Index();
23            List<string> list = new List<string>() { "中华", "中国", "人民", "中国人民", "人民" };
24            for (int i = 0; i < list.Count; i++)
25            {
26                Console.WriteLine("搜索词:" + list[i]);
27                Console.WriteLine("结果:");
28                Searcher(list[i]);
29                Console.WriteLine("-----------------------------------");
30            }
31        }
32
33        /// <summary>
34        /// 搜索
35        /// </summary>
36        /// <param name="querystring">搜索输入</param>
37        private void Searcher(string querystring)
38        {
39            Analyzer analyzer = new StandardAnalyzer();
40            IndexSearcher searcher = new IndexSearcher("IndexDirectory");
41            QueryParser parser = new QueryParser("content", analyzer);
42            Query query = parser.Parse(querystring);
43            Hits hits = searcher.Search(query);
44            for (int i = 0; i < hits.Length(); i++)
45            {
46                Console.WriteLine(hits.Doc(i).Get("content"));
47            }
48        }
49
50        /// <summary>
51        /// 索引数据
52        /// </summary>
53        private void Index()
54        {
55            Analyzer analyzer = new StandardAnalyzer();
56            IndexWriter writer = new IndexWriter("IndexDirectory", analyzer, true);
57            AddDocument(writer, "中华人民共和国");
58            AddDocument(writer, "中国人民解放军");
59            AddDocument(writer, "人民是伟大的,祖国是伟大的。");
60            AddDocument(writer, "你站在边上,我站在中央。");
61            writer.Optimize();
62            writer.Close();
63        }
64        /// <summary>
65        /// 为索引准备数据
66        /// </summary>
67        /// <param name="writer">索引实例</param>
68        /// <param name="content">需要索引的数据</param>
69        void AddDocument(IndexWriter writer, string content)
70        {
71            Document document = new Document();
72            document.Add(new Field("content", content, Field.Store.YES, Field.Index.TOKENIZED));
73            writer.AddDocument(document);
74        }
75    }
76}
77

 

代码2.1.2.1,先是把四句话进行了索引,尔后,分别用5个词进行了查询。运行结果:

 

搜索词:中华
结果:
中华人民共和国
-----------------------------------
搜索词:中国
结果:
中国人民解放军
-----------------------------------
搜索词:人民
结果:
中华人民共和国
中国人民解放军
人民是伟大的,祖国是伟大的。
-----------------------------------
搜索词:中国人民
结果:
中国人民解放军
-----------------------------------
搜索词:人民
结果:
中华人民共和国
中国人民解放军
人民是伟大的,祖国是伟大的。
-----------------------------------

发现结果还很不错,结果都在我们的预料之中,StandardAnalyzer分词器很好啊!为什么说它不行呢?接着,用StandardAnalyzer分词器为网站建立了索引,然后开始使用,问题就出现了。用户输入的往往不是一个词,而是几个词,或者干脆就是一句话。把问题简化一下,就用代码2.1.2.1作为模型。假如,现在索引进了四句话变成这样:

(1)、英语单词,语法,口语都很重要。

(2)、口语,语法,单词都是英语的重要组成部分。

(3)、我们要学好英语不但要学语法,单词还有口语。

(4)、对于学英语,只掌握单词语法,还是没办法跟别人沟通,必须能说出流利的口语。

 

假设,我们要搜索这四句话,也用5中输入:
(1)、英语

(2)、语法

(3)、单词

(4)、口语

(5)、英语单词

 

测试,结果对于输入的1,2,3,4前四个关键词,没问题,而第5个只能搜索到一个结果,这就纳闷了,明明每句话都包含了“英语”,“单词”这两个词汇,为什么不行呢?而把输入词换成“英语口语”,更邪门!没了,一个结果都没有。这是为什么呢?这个要从Lucene.Net的查询表达式说起。

 

话说,为了让Lucene.Net能灵活得搜索,因此,Lucene.Net引入了查询表达式,就和T-Sql的查询语句差不多,只是表现的代码不一样。现在对代码2.1.2.1做一个调整,在Query query = parser.Parse(querystring);语句下面加一句“Console.WriteLine(query.ToString());”,这个输出的就是查询表达式。而对于“英语单词”这个词,代码2.1.2.1会把它解析为——content:"英 语 单 词"——意思是在content字段,找“英”,“语”,“单”,“词”这四个字,并且,这四个字要连在一起。这显然不是我们想要的。而在用baidu或者google搜索的时候,如果输入的多个词之间加上空格就不一样了,同样,放到这里来试试。把词变成“英语 单词”,测试一下。

测试结果:

 

搜索词:英语 单词
结果:
content:"英 语" content:"单 词"
英语单词,语法,口语都很重要。
口语,语法,单词都是英语的重要组成部分。
我们要学好英语不但要学语法,单词还有口语。
对于学英语,只掌握单词语法,还是没办法跟别人沟通,必须能说出流利的口语。
-----------------------------------

 

可以搜素到了,而表达式也变成了——content:"英 语" content:"单 词"。

现在将面临新的问题:怎么才能把“英语单词”变成“英语 单词”。你不能期望用户总会输入搜索关键词后,逐个加上空格区分。而事实上一个新问题又产生了。修正一个错误会产生另外两个错误,前人说的太正确了。在这个例子里可能看不出来,把例子换一下,把上面第四句话换成“好好学英语”。

 

测试结果:

-----------------------------------
搜索词:英语 单词
结果:
content:"英 语" content:"单 词"
英语单词,语法,口语都很重要。
口语,语法,单词都是英语的重要组成部分。
我们要学好英语不但要学语法,单词还有口语。
好好学英语。
-----------------------------------

 

“好好学英语”没有包含“单词”这个词,但是却被搜索到了。这是为什么?玩我了吧?嘿嘿,那是因为——content:"英 语" content:"单 词"——这个表达式是或者的关系,要是变成并且的关系,是不是能解决问题呢?尝试手动改造下表达式。把表达式变成“+content:\"英 语\" +content:\"单 词\"”,测试:

 

-----------------------------------
搜索词:+content:"英 语" +content:"单 词"
结果:
+content:"英 语" +content:"单 词"
英语单词,语法,口语都很重要。
口语,语法,单词都是英语的重要组成部分。
我们要学好英语不但要学语法,单词还有口语。
-----------------------------------

 

very good !这个才是我们想要的嘛!怎么自己构造表达式,这个还是留到第四章来系统的讲。既然“+content:\"英 语\" +content:\"单 词\"”,可以用,那是不是“+content:\"英\" +content:\"语\" +content:\"单\" +content:\"词\"”,也可以使用呢?嘿嘿自己试试看吧。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/JIN20468320/archive/2008/10/23/3129592.aspx

加支付宝好友偷能量挖...


评论(0)网络
阅读(104)喜欢(1)lucene.net/分词技术