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

2.1.2 可以使用的内置分词

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

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

代码 2.1.2.1
 
Code 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;1011namespace Test12{13    [TestFixture]14    public class StandardAnalyzerCaseTest15    {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        }3233        /**//// <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        }4950        /**//// <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:\"词\"”,也可以使用呢?嘿嘿自己试试看吧。

Lucene.Net 2.3.1开发介绍 —— 二、分词(四)的更多相关文章

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

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(六) Lucene.Net的上一个版本是2.1,而在2.3.1版本中才引入了Next(Token)方法重载,而ReusableStrin ...

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

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(五) 2.1.3 二元分词 上一节通过变换查询表达式满足了需求,但是在实际应用中,如果那样查询,会出现另外一个问题,因为,那样搜索,是只 ...

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

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(三) 1.3 分词器结构 1.3.1 分词器整体结构 从1.2节的分析,终于做到了管中窥豹,现在在Lucene.Net项目中添加一个类关 ...

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

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(二) 1.2.分词的过程 1.2.1.分词器工作的过程 内置的分词器效果都不好,那怎么办?只能自己写了!在写之前当然是要先看看内置的分词 ...

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

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(一) Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来.目前Lucene.Net的分词库很不完善,实际应用价值不高.唯 ...

  6. Lucene.Net 2.3.1开发介绍 —— 四、搜索(二)

    原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(二) 4.3 表达式用户搜索,只会输入一个或几个词,也可能是一句话.输入的语句是如何变成搜索条件的上一篇已经略有提及. 4.3.1 观察 ...

  7. Lucene.Net 2.3.1开发介绍 —— 三、索引(二)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(二) 2.索引中用到的核心类 在Lucene.Net索引开发中,用到的类不多,这些类是索引过程的核心类.其中Analyzer是索引建立的 ...

  8. Lucene.Net 2.3.1开发介绍 —— 三、索引(四)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(四) 4.索引对搜索排序的影响 搜索的时候,同一个搜索关键字和同一份索引,决定了一个结果,不但决定了结果的集合,也确定了结果的顺序.那个 ...

  9. Lucene.Net 2.3.1开发介绍 —— 四、搜索(三)

    原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(三) Lucene有表达式就有运算符,而运算符使用起来确实很方便,但另外一个问题来了. 代码 4.3.4.1 Analyzer anal ...

随机推荐

  1. Pison geeker

    Pison on scriptogr.am Pison Abraham Lincoln: "Nearly all men can stand adversity, but if you wa ...

  2. hdu 1395 2^x mod n = 1 (简单数论)

    题目大意: 求出一个最小的x 使得 2的x次方对n取模为1 思路分析: 若要 a*b%p=1  要使得b存在 则 gcd (a,p)=1. 那么我们应用到这个题目上来. 当n为偶数 2^x 也是偶数, ...

  3. Android中如何查找内存泄露

    1.首先确定是否有内存泄露及哪个程序造成. 1.1.内存泄露已弹出out of memory对话框的情况. 这种情况很简单,直接看对话框就知道是哪个应用的问题了.然后再分析该应用是否是因为内存泄露造成 ...

  4. Reverse Words in a String | LeetCode OJ | C++

    我的思路:先读取每一个单词,存放到容器中:读取完毕后,将容器中的单词倒序写入输出中. #include<iostream> #include<string> #include& ...

  5. c# 课堂总结7--函数

    函数:数据类型-变量类型-运算符号表达式-语句(顺序,分支,循环)-数字 程序里的函数:能完成一个相对独立功能的代码块.数学里的函数:高度抽象.函数四要素:函数名,输入(参数),输出(返回值类型),加 ...

  6. 二叉树的前序和中序得到后序 hdu1710

    今天看学长发过来的资料上面提到了中科院机试会有一个二叉树的前序中序得到后序的题目.中科院的代码编写时间为一个小时,于是在七点整的时候我开始拍这个题目.这种类型完全没做过,只有纸质实现过,主体代码半个小 ...

  7. [转]mysql慢查询日志

    原文链接:http://www.cnblogs.com/zhangjing0502/archive/2012/07/30/2615570.html 参考博文:http://blog.chinaunix ...

  8. inet_addr() inet_ntoa() inet_pton inet_ntop sockaddr_in

    inet_addr() 简述:将一个点间隔地址转换成一个in_addr.#include <winsock.h>unsigned long PASCAL FAR inet_addr( co ...

  9. stringstream clear()的疑问 - yuanshuilee的日志 - 网易博客

    stringstream clear()的疑问 - yuanshuilee的日志 - 网易博客 stringstream clear()的疑问   2013-09-05 08:43:13|  分类: ...

  10. Linux下搭建Hadoop集群

    本文地址: 1.前言 本文描述的是如何使用3台Hadoop节点搭建一个集群.本文中,使用的是三个Ubuntu虚拟机,并没有使用三台物理机.在使用物理机搭建Hadoop集群的时候,也可以参考本文.首先这 ...