`
sealbird
  • 浏览: 586447 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Clucene实现中文分词搜索(转载)

阅读更多
Clucene实现中文分词搜索(转载)2008年05月23日 星期五 17:42最近,一阵忙乎,终于在Clucene(版本0.9.16)中实现了中文分词搜索。


一些需要改动的地方如下:
     
             一、 把项目设置为Use Unicode Character Set。因为使用ANSI时,汉字存在与其他语言编码重叠的问题,不能准确判断是否为汉字。
  
             二、 \src\CLucene\util\Misc.cpp中有个Misc::_cpycharToWide函数,这个函数是CLucene中用来将char 字符串转换为wchar_t字符串的,但原代码中使用的是不考虑编码的转换,把汉字从ANSI编码转到UCS2编码会失效,所以需要在\src\ CLucene\StdHeader.h的宏定义中,改用windows API的MultiByteToWideChar函数。
line350 改为#define STRCPY_AtoW(target,src,len) MultiByteToWideChar(936,0,src,-1,target,len);


\src\CLucene\util\Misc.cpp,line67的Misc::_charToWide函数调用了_cpycharToWide函数,需修改。

            三、 要实现中文按词搜索必须按中文语法实现Analyzer接口。Clucene里面有一个StandardAnalyzer类,它本意是可以处理亚洲语言 (包括中日韩),但不完善。可以通过改写 \src\CLucene\analysis\standard\StandardTokenizer.cpp文件来达到目的。
           其中,有一个StandardTokenizer::next(),用来获取下一个token。Token可以简单看成是索引文件中的一个项。在原代码 中,先判断是否为ALPHA,再判断是否为_CJK,而在中文windows系统上,将一个UCS2编码的汉字(正好一个wchar_t)作为参数传给 iswalpha函数时,返回值是true。所以任何CJK字符都会被处理成ALPHA。因此,项目修改为使用Unicode编码后,ReadCJK函数 不会被调用到。所以需要将原代码中的if(_CJK)的判断分支放到if(ALPHA)前面,这样遇到CJK字符时就会调用 StandardTokenizer::ReadCJK。
            ReadCJK函数用于读取一个CJK的token。这个函数不能处理中文分词,它遇到CJK字符时一直向后读取,直到遇到非CJK字符或文件结束才跳出,把读取到的整个字符串作为索引中的一个项。所以需要重写这个函数。
           我在StandardAnalyzer类加入了一个公有类paticiple,这个paticiple类有一个方法 ParagraphProcessing(char *str,char *result),可以用来把一个char类型的中文字符串str进行分词,由result返回分词结果,词与词之间用空格格开。以下是我重写的 ReadCJK函数:

 
   bool StandardTokenizer::ReadCJK(const TCHAR prev, Token* t) 
{
             t->growBuffer(LUCENE_MAX_WORD_LEN+1);//make sure token can hold the next word
             StringBuffer str(t->_termText,t->bufferLength(),true); 
             if ( str.len < LUCENE_MAX_WORD_LEN )
           { 
                  str.appendChar(prev);
                  TCHAR ppl[10];    //临时存放从Tokenstream读出的不大于八个汉字的字符用于分词,因为中文词语最长为八 
                   ppl[0]= prev; 
                   int i;
                   int time=0;       //记录指针往前移动的位置 
                   for(i=1;i<8;i++)        //读取八个CJK字符,若中间有非CJK字符则跳出,追加‘\0‘结尾形成字符串
                 { 
                         ppl[i]=readChar();time++;
                         if       (ppl[i]==-1 || (!( (ppl[i]>=0x3040 && ppl[i]<=0x318f) ||       (ppl[i]>=0x3300 && ppl[i]<=0x337f) || \
                                                         (ppl[i]>=0x3400 && ppl[i]<=0x3d2d) ||       (ppl[i]>=0x4e00 && ppl[i]<=0x9fff) || \
                                                         (ppl[i]>=0xf900 && ppl[i]<=0xfaff) ||       (ppl[i]>=0xac00 && ppl[i]<=0xd7af) ) ) )
                      {
                             break; 
                       }
                  }//for
                  ppl[i]=0;
                  for( ;time>0;time--)       //还原指针 
                        unReadChar();
               //把PPL转换成CHAR类型ppltemp,利用paticiple类分词,把最终TCHAR型的分词结果存放在 pplnew里面 

               len=WideCharToMultiByte(936,0,ppl,-1,NULL,0,NULL,NULL);
                char* ppltemp=new char[len+1];
                WideCharToMultiByte(936,0,ppl,-1,ppltemp,len,NULL,NULL);
                char* pplnewtemp=new char[2*len+1];
                paticiple.ParagraphProcessing(ppltemp,pplnewtemp);
                int length=MultiByteToWideChar(936,0,pplnewtemp,-1,NULL,0);
                TCHAR pplnew[20]; 
                MultiByteToWideChar(936,0,pplnewtemp,-1,pplnew,length); 
                delete[] ppltemp;
                delete[] pplnewtemp; 
               //改从pplnew中读取字符而不是从tokenstream中
                 int j=1;
                 while(true)
                {
                      ch=pplnew[j]; 
                       if(!rd->Eos())
                     {
                           int k=readChar();        //使readChar()的指针与从pplnew[]中读出的字符保持同步
                      }
                       if (ch==-1 || (!(_CJK) || str.len >= LUCENE_MAX_WORD_LEN))
                     { 
                       unReadChar();
                       break; 
                     } 
                      str.appendChar(ch);
                      j++;
               }//while
          }//if
          return setToken(t,&str,CL_NS2(analysis,standard)::CJK);
}
  
             四、如果一个中文句子中引入了英文单词,则进入英文处理函数ReadAlphaNum()后,由于引用了宏CONSUME_WORD,对英文后面出现的中 文会继续作为Alpha字符处理,索引为一个项,直到遇到非Alpha字符为止。为了避免英中文连用(中间没有空格)时索引出错,还要修改 StandardTokenizer.cpp中的宏定义,
line 42,改为#define _CONSUME_AS_LONG_AS(conditionFails) while (true) { ch = readChar(); if (ch==-1 ||
(!(conditionFails) || str.len >= LUCENE_MAX_WORD_LEN) ||_CJK) { break; } str.appendChar(ch);}
这样,当当前字符为ALPHA,而下一个字符为CJK时,就可以从宏CONSUME_WORD 中跳出。
另外,StandardTokenizer::ReadAlphaNum()中有个switch(ch)语句,在最后一行加上default:unReadChar();这样可以保证不漏掉跳出后,英文单词后紧跟的第一个CJK字符。

             五、输入的查询语句在转化为QUERY对象时必须以标点符号结束,否则会被处理为一个不完整句子,最后的几个字符不能写入索引项。

ps:为了能显示wchar_t类型的字符串,还必须使用Wcout函数代替 printf函数。   ^_^

分享到:
评论

相关推荐

    clucene中文处理

    除了上述核心功能,"clucene中文处理"还可能涉及其他方面,如繁体字与简体字的兼容、拼音转换(方便用拼音进行搜索)以及对UTF-8编码的支持等。这些都需要对Clucene的源代码进行深入理解和修改。 总的来说,...

    C++搜索引擎Clucene源码

    在Clucene的源码中,我们可以看到这些组件的具体实现,例如`TokenStream`接口定义了分词流的行为,`Analyzer`类负责整个分词过程,`IndexWriter`类处理索引的建立和更新,`IndexReader`用于读取索引,`QueryParser`...

    搜索引擎 CLucene 源代码

    CLucene 是一个基于 C++ 的全文搜索引擎库,它是 Lucene 的 C++ 实现。Lucene 是 Java 语言开发的一个著名开源全文检索库,被广泛应用于各种项目中,提供了高效的文本检索和分析功能。CLucene 旨在为那些希望在 C++ ...

    C++搜索引擎 CLucene源码

    4. **文本分析**:CLucene支持多种语言的文本分析,包括分词、去除停用词、词干化等,这些预处理步骤对于提高搜索精度至关重要。 5. **倒排索引**:CLucene采用了倒排索引这一高效的数据结构,通过记录每个词在哪些...

    CLucene

    CLucene是基于C++语言实现的一个全文搜索引擎库,它是对Java版Lucene的移植,旨在为C++开发者提供与Lucene类似的搜索功能。Lucene是一个广泛使用的开源信息检索库,由Apache软件基金会维护,它提供了丰富的文本分析...

    Clucene库以及自己封装好的Clucene方法库

    Clucene库是一个开源的全文搜索引擎库,它是Lucene的C++版本,旨在为C++开发者提供高效、稳定的文本检索功能。Lucene是一个广泛使用的搜索引擎框架,由Java编写,而Clucene则是将其移植到了C++环境,保留了Lucene的...

    luceneDemo_pure1aa_DEMO_clucene_

    Clucene是Lucene的C++实现,它继承了Lucene的核心功能,包括文本分析、索引构建、搜索等功能。Clucene的目标是提供一个与Lucene功能相当且易于集成到C++项目的搜索引擎库。 二、vc6环境准备 在vc6中使用Clucene,...

    CLucene 最新源码

    1. **分词器(Tokenizer)**:CLucene提供了一系列的分词器,如StandardAnalyzer,用于将输入的文本分解成可搜索的关键词。分词器可以根据不同的语言进行定制,以适应各种文本处理需求。 2. **文档(Document)**:...

    CLucene源代码-Lucene的C++版本

    CLucene是Lucene的C++实现,为那些偏好或需要使用C++进行开发的程序员提供了在C++环境中构建全文搜索引擎的可能。Lucene是一个高性能、全文本搜索库,由Java编写,广泛应用于各种搜索引擎和信息检索系统。CLucene则...

    搜索引擎开源代码Clucene-core-0.9.21

    Clucene-core-0.9.21是一款基于C++实现的开源搜索引擎库,它提供了类似于Java Lucene的功能,使得开发者能够方便地在C++环境中构建全文检索应用。这个压缩包包含了Clucene的核心源代码,对于想要理解搜索引擎工作...

    clucene源码

    大名鼎鼎的clucene,是lucene的c++ 版; CLucene README ============== ------------------------------------------------------ CLucene is a C++ port of Lucene. It is a high-performance, full-featured ...

    clucene-0.9.10.tar

    总的来说,Clucene-0.9.10为C++开发者提供了一个强大的信息检索工具,使得在C++应用中实现全文搜索变得简单高效。无论是构建搜索引擎,还是在企业级应用中实现文档检索,Clucene都是值得信赖的选择。通过深入学习和...

    clucene2.3.3.4源码 windows下vs2013工程

    CLucene是一款开源的全文搜索引擎库,它基于C++编写,为开发者提供了一种高效、可扩展的全文检索解决方案。在本文中,我们将详细探讨如何在Windows操作系统上使用Visual Studio 2013来编译和理解CLucene 2.3.3.4版本...

    lucene及分词工具说明

    分词工具基于厦门大学人工智能研究所开发的分词工具DLL进行封装,用于实现中文文本的分词功能。 ##### 函数说明 1. **`int init()`** - 初始化函数,用于加载`segtag.dll`。如果加载成功,该函数返回1;否则返回...

    Clucene库以及自己封装的方法库(补充)——对应的头文件和.lib索引文件

    总的来说,这个压缩包提供了Clucene库的头文件和可能经过封装的DLL,帮助开发者更方便地在C++项目中实现全文搜索引擎功能。这包括创建索引、执行查询和检索相关文档,从而提升项目的搜索效率和用户体验。为了使用...

    CLUCENE资料合集+代码源码

    这是我学CLUCENE时期整理出来的几个不错的资料,我觉得里面总有一款会适合你,而且你所需要知道的技术里面基本上都是涵盖的,所以可以当作教材或者参考手册使用。(里面有CLUCENE,可以用的)

    clucene-core lucene c

    Lucene是apache组织的一个用java实现全文搜索引擎的开源项目。 其功能非常的强大,api也很简单。总得来说用Lucene来进行建立 和搜索和操作数据库是差不多的(有点像),Document可以看作是 数据库的一行记录,Field...

    clucene-core-2.3.3.4 cmake可生产vs2005工程

    1. **Clucene**:Clucene是一个C++实现的全文搜索引擎库,它是对Java的Lucene搜索引擎的移植,旨在提供高性能、可扩展的文本搜索功能。它支持索引和搜索大量文本数据,并且可以嵌入到各种C++应用程序中。 2. **...

    clucene_32位

    CLucene,作为一个开源的全文搜索引擎库,是C++编程语言中实现Lucene搜索技术的实现。本文将深入探讨CLucene的核心概念、安装配置过程以及如何利用它来构建高效能的全文检索应用。 一、CLucene简介 CLucene是Java ...

Global site tag (gtag.js) - Google Analytics