博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lucene.net 搜索引擎中中文词组分词的实现
阅读量:4968 次
发布时间:2019-06-12

本文共 8253 字,大约阅读时间需要 27 分钟。

 Lucene.net标准分词器在英文分词中有非常好的体验。比喻说:在邮件,IP地址,符号处理方面,它都处理得非常好。只是很遗憾,它不支持中文词组分词。于是,我就通过修改里面的核心代码让它扩展,支持中文的分词。

目标:使它能够增加对中文词组的切词。

效果:

原句:“我是中国人!I am chiness!Email:youpeizun126@126.com;IP:172.17.34.168”

切词效果:

我/是/中国人/中国/中/国/人/Email/youpeizun126@126.com/IP/172.17.34.168

所要完成的任务:

1. 装载词库

2. 截取一段连续的中文字段

3. 进行连续的分词.

下面是设计扩展Lucene.net标准分词器的支持中文词组分词的流程图.
       接下来,我把扩展Lucene.net标准分词器所写的核心代码,主要包含三个函数,它们分别实现装载词典,载取连续中文字段,中文词组分词算法功能.

中文词组分词核心代码
#region 加载中文词典        public  void LoadDirectory(string path)        {            if(!File.Exists("words.txt"))                return;           TextReader tr_words=new StreamReader("words.txt",System.Text.Encoding.Default);            System.Diagnostics.Debug.Write("begin read words");                if(directory==null)          {                     directory=new System.Collections.Hashtable();                    try                    {                        string word=null;                        while((word=tr_words.ReadLine())!=null)                        {                            try                            {                                if(directory[word]==null)                                {                                directory.Add(word,word);                                                                }                            }                            catch(SystemException ex_)                            {                                                        }                        }                    }                    catch(SystemException ex)                    {                                        }          }#endregion                   }#region 截取一段连续中文字段        private void  InitChinessText()        {                        textlengh=0;                    cn_index=0;            chinesstext[0]=token.image;            textlengh++;            cn_start=token.beginColumn;            isCnToken=true;             bool isCN= true;                        while(isCN&&textlengh<255)            {   token=token_source.GetNextToken();                if(token.kind!=0)                {                    isCN=Char.GetUnicodeCategory(token.image,0).Equals(System.Globalization.UnicodeCategory.OtherLetter);                }                else                    isCN=false;                if(isCN)                {                                                                                             chinesstext[textlengh]=token.image;                                textlengh++;                }                else                {                                        cn_end_token=token;                }                        }            if(textlengh>=4)            {            wordlengh=4;            }            else                wordlengh=textlengh;                                    }#endregion#region 实现中文分词算法        private string GetNextTokenText()        {   string text=null;                     if(wordlengh==4)            {                text=chinesstext[cn_index]+chinesstext[cn_index+1]+chinesstext[cn_index+2]+chinesstext[cn_index+3];                if(directory[text]!=null)                {                                    }                wordlengh--;            }            if(wordlengh==3)            {                text=chinesstext[cn_index]+chinesstext[cn_index+1]+chinesstext[cn_index+2];                wordlengh--;                if(directory[text]!=null)                {                goto return_;                }                            }            if(wordlengh==2)            {                text=chinesstext[cn_index]+chinesstext[cn_index+1];                wordlengh--;                if(directory[text]!=null)                {                    goto return_;                }                        }            if(wordlengh==1)            {                text=chinesstext[cn_index];                cn_index++;                if((textlengh-cn_index)>=4)                {                    wordlengh=4;                }                else                    if((textlengh-cn_index)==0)                {                    isCnToken=false;                    jj_ntk=cn_end_token.kind;                    token=new Token();                    token.next=cn_end_token;                                }                else                {                wordlengh=textlengh-cn_index;                }                        }            return_:                return text;        }        #endregion        */

  

        

 

一、中文分词方式:

中文分词几种常用的方式:

A. 单字分词

单字分词,顾名思义,就是按照中文一个字一个字地进行分词。如:我们是中国人,效果:我\们\是\中\国\人。

B. 二分法

二分法,就是按两个字进行切分。如:我们是中国人,效果:我们\们是\是中\中国\国人。

C. 词库分词

词库分词,就是按某种算法构造词然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语。通常词库分词被认为是最理想的中文分词算法如:我们是中国人,通成效果为:我们\是\中国\中国人。

二、Lucene.net中五种中文分词效果探究

在Lucene.net中有很多种分词器,不同分词器使用了不同的分词算法,有不同的分词效果,满足不同的需求!在这里主要是看看其中五中分词器用来对中文切词的效果。五中分词器分别为:StandardTokenizer,CJKTokenizer,ChinessTokenizer,LowerCaseTokenizer,WhitespaceTokenizer;

   下面就来测试一下它们切词的效果:

   测试目标:是否支持中文词语,英文单词,邮件,IP地址,标点符号,数字,数学表达式的切割。

   测试文字:“我们是中国人; 我们 是 人;we are chiness; 172.16.34.172;youpeizun@126.com;#$*;85*34;58 69”

 

测试StandardTokenizer的分词情况如下:

我/ 们/ 是/ 中/ 国/ 人/ 我/ 们/ 是/ 人/ we/ are/ chiness/ 172.16.34.172/ youpeizun@126.com/ 85/ 34/ 58/ 69/

测试CJKTokenizer的分词情况如下:

我们/ 们是/ 是中/ 中国/ 国人/ 我们/ 是/ 人/ we/ chiness/ 172/ 16/ 34/ 172/ youpe

izun/ 126/ com/ #/ 85/ 34/ 58/ 69/

测试ChinessTokenizer的分词情况如下:

我/ 们/ 是/ 中/ 国/ 人/ 我/ 们/ 是/ 人/ we/ are/ chiness/ 172/ 16/ 34/ 172/ youp

eizun/ 126/ com/ 85/ 34/ 58/ 69/

测试LowerCaseTokenizer的分词情况如下:

我们是中国人/我们/是/人/we/are/chiness/youpeizun/com/

测试WhitespaceTokenizer的分词情况如下:

我们是中国人;/我们/是/人;we/are/chiness;/172.16.34.172;youpeizun@126.com;#$*;85*

34;58/69/

 

测试代码: 

using System;
using System.Collections.Generic;
using System.Text;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using System.IO;
using Lucene.Net.Analysis.Cn;
using Lucene.Net.Analysis.CJK;
//date:11-02-2007
//home page:http://www.cnblogs.com/xuanfeng
//author:peizunyou
namespace TokenizerTest
{
    class TokenizerTest
    {
        static void Main(string[] args)
        {
            string testText = "我们是中国人; 我们 是 人;we are chiness; 172.16.34.172;youpeizun@126.com;#$*;85*34;58 69";
            Console.WriteLine("测试文字:"+testText);
            Console.WriteLine("测试StandardTokenizer的分词情况如下:");
            TestStandardTokenizer(testText);
            Console.WriteLine("测试CJKTokenizer的分词情况如下:");
            TestCJKTokenizer(testText);
            Console.WriteLine("测试ChinessTokenizer的分词情况如下:");
            TestChinessTokenizer(testText);
            Console.WriteLine("测试LowerCaseTokenizer的分词情况如下:");
            TestLowerCaseTokenizer(testText);
            Console.WriteLine("测试WhitespaceTokenizer的分词情况如下:");
            TestWhitespaceTokenizer(testText);
            Console.Read();
        }
        static  void TestStandardTokenizer(string text)
        {
            TextReader tr = new StringReader(text);
            StandardTokenizer st = new StandardTokenizer(tr);
         
            while (st.Next() != null)
            {
                Console.Write(st.token.ToString()+"/ ");
            }
            Console.WriteLine();
        }
        static void TestCJKTokenizer(string text)
        {
            TextReader tr = new StringReader(text);
            int end = 0;
            CJKAnalyzer cjkA = new CJKAnalyzer();
            TokenStream ts = cjkA.TokenStream(tr);
            while(end<text.Length)
            {
                Lucene.Net.Analysis.Token t = ts.Next();
                end = t.EndOffset();
                Console.Write(t.TermText()+"/ ");
            }
            Console.WriteLine();
        }
        static void TestChinessTokenizer(string text)
        {
            TextReader tr = new StringReader(text);
            ChineseTokenizer ct = new ChineseTokenizer(tr);
            int end = 0;
            Lucene.Net.Analysis.Token t;
            while(end<text.Length)
            {
                t = ct.Next();
                end = t.EndOffset();
                Console.Write(t.TermText()+"/ ");
            }
            Console.WriteLine();
        
        }
        
        static void TestLowerCaseTokenizer(string text)
        {
            TextReader tr = new StringReader(text);
            SimpleAnalyzer sA = new SimpleAnalyzer();
            //SimpleAnalyzer使用了LowerCaseTokenizer分词器
            TokenStream ts = sA.TokenStream(tr);
            Lucene.Net.Analysis.Token t;
            while((t=ts.Next())!=null)
            {
                Console.Write(t.TermText()+"/");
            }
            Console.WriteLine();
        }
        static void TestWhitespaceTokenizer(string text)
        {
            TextReader tr = new StringReader(text);
   
            WhitespaceAnalyzer sA = new WhitespaceAnalyzer();
            TokenStream ts = sA.TokenStream(tr);
            Lucene.Net.Analysis.Token t;
            while ((t = ts.Next()) != null)
            {
                Console.Write(t.TermText() + "/");
            }
            Console.WriteLine();
        }
    }
}

三、            五中分词器代码设计探究

       从下面分词器代码设计中的静态结构图可以清晰的看出其继承关系。无论是哪个分词器,其分词最终实现的算法都是在Next()方法,想深入了解,请看其相关源码。

转载于:https://www.cnblogs.com/haiyabtx/archive/2012/11/14/2770126.html

你可能感兴趣的文章
Python模块调用
查看>>
委托的调用
查看>>
c#中从string数组转换到int数组
查看>>
数据模型(LP32 ILP32 LP64 LLP64 ILP64 )
查看>>
java小技巧
查看>>
POJ 3204 Ikki's Story I - Road Reconstruction
查看>>
【BZOJ】2959: 长跑(lct+缩点)(暂时弃坑)
查看>>
iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?
查看>>
toad for oracle中文显示乱码
查看>>
SQL中Group By的使用
查看>>
错误org/aopalliance/intercept/MethodInterceptor解决方法
查看>>
两个表格中数据不用是一一对应关系--来筛选不同数据,或者相同数据
查看>>
客户数据库出现大量cache buffer chains latch
查看>>
機械の総合病院 [MISSION LEVEL: C]
查看>>
实战练习细节(分行/拼接字符串/字符串转int/weak和copy)
查看>>
Strict Standards: Only variables should be passed by reference
查看>>
hiho_offer收割18_题解报告_差第四题
查看>>
AngularJs表单验证
查看>>
静态方法是否属于线程安全
查看>>
02号团队-团队任务3:每日立会(2018-12-05)
查看>>