最近,一阵忙乎,终于在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实现中文分词搜索(转载)相关推荐

  1. php 搜索引擎 分词_PHP 实现中文分词搜索功能

    中文分词介绍 众所周知,英文是以词为单位的,词和词之间是靠空格隔开,而中文是以字为单位,句子中所有的字连起来才能描述一个意思.例如,英文句子I am a student,用中文则为:"我是一 ...

  2. PHP 实现中文分词搜索功能

    中文分词介绍 众所周知,英语是基于单词的,单词和单词之间用空格隔开,而中文是基于单词的.句子中的所有单词都可以连接起来以描述含义.例如,英文句子"我是学生"将用中文表示" ...

  3. php scws 获取分词结果,php实现scws中文分词搜索的方法

    本文实例讲述了php实现scws中文分词搜索的方法.分享给大家供大家参考,具体如下: 1.4个文件(本站下载地址.)解压后,放到一个地方 eg:E:/wamp/scws 2.php.ini 中配置 e ...

  4. mysql 中文分词搜索_php中文分词搜索

    本篇文章主要介绍php中文分词搜索,感兴趣的朋友参考下,希望对大家有所帮助. 1.4个文件(本站下载地址.)解压后,放到一个地方 eg:E:/wamp/scws 2.php.ini 中配置 exten ...

  5. java之全文索引搜索lucene之增删改查文档与中文分词搜索

    java之全文索引搜索lucene之增删改查文档与中文分词搜索 接上文,接下来介绍一个lucene的各种query,然后介绍一下中文全文索引搜索. 对于各种query,我就直接上代码了,具体的话,我已 ...

  6. 一行命令让ElasticSearch支持中文分词搜索

    相信大家在开发博客,在线商城的时候会涉及到搜索功能.而近几年火起来的 ElasticSearch(ES)凭借其稳定.可靠.快速的实时搜索普遍受到大家的好评,连 Github.SoundCloud 也都 ...

  7. Laravel5.4中文分词搜索-使用 Laravel Scout,Elasticsearch,ik 分词(三)

    上一篇地址:https://blog.csdn.net/huangfenhu/article/details/94009241 创建一个文章表和文章模型: php artisan make:model ...

  8. Laravel5.4中文分词搜索-使用 Laravel Scout,Elasticsearch,ik 分词(一)

    elasticsearch需要的环境搭建 简介: 使用elasticsearch的前提是你的主机必须安装了java的JDK,而且版本必须是1.8以上,并设置JAVA_HOME环境变量 java的jdk ...

  9. mysql 中文分词搜索_利用中文分词打造数据库全文检索

    传统的 LIKE 模糊查询(前置百分号)无法利用索引,特别是多个关键词 OR,或在多个字段中 LIKE,更是效率低下.本文研究对文章进行分词以提高检索的准确度和查询效率. 根据自己的编程语言选择一款合 ...

最新文章

  1. spine - unity3D(摘自博主softimagewht)
  2. 苏宁11.11:苏宁易购订单搜索系统架构及实现
  3. 磁盘管理 ——RAID1+0卷+LVM
  4. php 使用压缩css文件,PHP-使用GZIP压缩静态CSS文件
  5. mysql8出现The MySQL server is running with the --skip-grant-tables option so it cannot execute
  6. 黑马程序员--ADO.Net中的知识点和难点
  7. c++常用知识点,易错点,面试常问点
  8. JVM整体架构与调优参数说明
  9. 南阳理工oj 题目26 孪生素数问题 素数筛选法
  10. 回归预测 基于ELMAN递归神经网络预测及其matlab代码实现
  11. Xftp6+Xshell6+XmanagerPowerSuite安装教程
  12. QT实现记事本代码(版本三)
  13. easyui基本布局
  14. 木马手工查杀和隐藏控制技术分析
  15. Grafana的短信报警
  16. 【webrtc】 CongestionControlHandler 的 RTC_DCHECK_RUN_ON(sequenced_checker_);
  17. dz php debug,开发dz插件后台提示错误
  18. ubuntu目录结构简述
  19. Vue3 的生命周期函数
  20. CSS div内文字溢出部分隐藏显示...省略号

热门文章

  1. OSPF基本概念单与区域配置
  2. ubuntu 12.04 LTS 安装配置JDK1.6.0_45
  3. Xcode5打包静态库
  4. 做好准备,让你的短信应用迎接Android 4.4(KitKat)
  5. onCreate onRestoreInstanceState onSaveInstanceState
  6. Python自动化开发学习的第九周----线程、进程、协程
  7. Android RoboGuice开源框架、Butter Knife开源框架浅析
  8. Linux2.6.32内核笔记(5)在应用程序中移植使用内核链表【转】
  9. HttpURLConnection类的使用
  10. 用GO语言开发editplus编辑器插件(附源码)