庖丁解牛 最新版本2.0.0

主要变更:

1)调整了package命名 改为net.paoding.analysis开头;调整了一些类的命名,主要是XAnalyzer改为
PaodingAnalyzer之类的。

2)并调整了部分代码的相对位置:代码集中在三个包中:
net.paoding.analysis.dictionary 字典抽象--这是核心代码之一
net.paoding.analysis.knife "刀"抽象-分词算法-这是核心代码之二
net.paoding.analysis.analyzer 封装adapter到lucene接口
关键代码没有任何改变,特别是CJKKnife没有发现错误。

3)同时,将字典改为英文命名,避免操作系统中文命名带来不必要影响

4)增加了配置文件;使knife可以在配置文件配置增减,同时字典的安装路径可以随意指定。

5)BUGFIX : highlight位置错误

下载地址:http://code.google.com/p/paoding/downloads/list
SVN地址:http://paoding.googlecode.com/svn/trunk/paoding-analysis/

-------------------------------------------------------------------
选择"庖丁解牛"作为Lucene中文分词可能有以下理由:

@设计优美-使用庖丁隐喻,容易理解代码设计

@效率极高-极高效率的字典查找算法;尽量避免无谓试探查找

@算法简练-简单易理解的算法,但效率却是非常高效的

@轻松支持最大/最小切词

@字典灵活-
字典文件个数不限;
名称不限,只要符合以dic作为扩展名的均视为字典
目录层级不限(所以可以任意加减字典目录以及目录下的字典)
字典格式简单:不需要特别排序,人工可编辑

@源代码是开放的,遵守http://www.apache.org/licenses/LICENSE-2.0协议

@作者能力:Java基础知识、设计能力扎实、持续关注改进

-------------------------------------------------------------------
"庖丁解牛" 使用指南

1、准备
1)将二进制包paoding-analyis.jar放到自己的classpath下

2)将字典文件安装(也就是拷贝)到某个目录下,比如/data/paoding/dic下

3)把配置文件paoding-analysis.properties放到自己的classpath下

4)打开paoding-analysis.properties,把paoding.dic.home属性设置为字
典的安装目录,比如paoding.dic.home=/data/paoding/dic,特别的,如
果字典是安装在classpath下的dic目录下,则可以简单这样配置该属性:
paoding.dic.home=classpath:dic

2、建立索引
1)将庖丁封装成符合Lucene要求的Analyzer规范,获取writer mode的lucene
分析器,writer mode意味要同时支持最大和最小切词。
Paoding paoding = PaodingMaker.make();
Analyzer writerAnalyzer = PaodingAnalyzer.writerMode(paoding);

Paoding应保存为一个系统单例为好,以重复利用,它是线程安全的.

2)使用Lucene标准API对文件建立索引。
IndexWriter writer = new IndexWriter(dirctory, writerAnalyzer);
...

3、检索查找
1)使用Lucene标准API对文件进行检索,使用和建立索引时相同种的lucene分析器。
QueryParser parser = new QueryParser("content", writerAnalyzer );
...

更具体的使用方式参见
examples/net.paoding.analysis.examples.gettingstarted中的示例代码

------------------------------------------------------------------
"庖丁解牛"google 论坛:
http://groups.google.com/group/paoding

"中文分词" Javaeye 论坛:
http://analysis.group.javaeye.com/

svn地址:
http://paoding.googlecode.com/svn/trunk/paoding-analysis/

旧版本地址:
http://paoding.googlecode.com/svn/trunk/paoding-analysis-1/
不建议下载旧版本
评论
Qieqie 2007-09-03
高亮的问题是1.x的bug,已经在2.x修改,现在不存在这个问题。

上面rainsf是因为其修改了代码,未改回来导致的。---rainsf最终给我的邮件说明的。

所以,请确认是用的是2.x的。 如有疑问,站内短信联系为佳。

谢谢。
hlgao 2007-09-03
高亮确实有些问题,我也好奇怪的。
看了你们的说法,我换用netbeans 5.5.1重新编译了一下,发现高亮还是有问题的,会出现一些无关的内容。
dwangel 2007-08-27
rainsf 写道
我终于发现在“高亮错误”的可笑原因,在JDK1.6环境下,直接命令行来运行那几个例子,高亮就没有问题,但我在Eclipse下无论用JDK1.5还是JDK1.6,编译级别无论用5还是6,高亮都一样是错误的,在Tomcat环境下运行情况同样。以上情况看起来很可笑。
真的很郁闷,具体原因出在哪里,还没有时间考究,只知道有这样的事实。切切.王,你也在Eclipse或服务器环境下,或JDK1.5下试试吧,看看情况怎样。。。


eclipse用的编译器是自己改造过的。
如果,是仅在eclipse下出问题,可以考虑用jdk的默认编译器编译下。
ant+javac
lazywalker 2007-08-19
我封装了一下,在solr1.2版本中测试通过,希望对您有用,也为了享受paoding的同时出一份力:

把附件 mysolr.jar 和 paoding-analysis.jar/commons-logging.jar 拷贝到solr实例的lib目录下(默认不存在,需要自己建立),
编辑schema.xml,加上对mysolr.analysis.ChineseTokenizerFactory的配置节
<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
          <tokenizer class="mysolr.analysis.ChineseTokenizerFactory" mode="index"/>
           .....
      </analyzer>
      <analyzer type="query">
	  <tokenizer class="mysolr.analysis.ChineseTokenizerFactory" mode="query"/>
          .....
      </analyzer>
</fieldType>

ps:之所以使用mode=index来代替mode=write,是因为我觉得index更加符合lucene的习惯,呵呵

lanhuai 写道
希望能够提供Solr的解决方案

在Spring中比较好配置,但是在Solr中好像没有类似Spring的<property name="knife" ref="paoding"/>的方式

Qieqie 写道
rainsf 写道

2、最终的Analyer子类(PaodingAnalyzer),应该提供一个无参构造器,因为大多数框架通常都是配置指定Analyer实现类通过反映加载Analyer的,如Hibernate Search.


参见:
JavaEye:Spring Context下使用"庖丁解牛"
或:
Google:Spring Context下使用"庖丁解牛"

简单摘要(以上面两个链接中的说明为准,这里只是摘要):

   <bean id="writerAnalyzer" class="net.paoding.analysis.analyzer.PaodingAnalyzer">
       <property name="knife" ref="paoding"/>
       <property name="mode" value="1"/>
   </bean>

   <bean id="queryAnalyzer" class="net.paoding.analysis.analyzer.PaodingAnalyzer">
       <property name="knife" ref="paoding"/>
       <property name="mode" value="2"/>
   </bean>

   <bean id="paoding" class="net.paoding.analysis.knife.PaodingMaker"  factory-method="make"/>


---------
补:
1、建立索引和使用索引只能使用同一种/模式的分词器
2、2.0.2以后(包含)queryMode和writerMode这两个名称将重构为更好的名称,请留意倒是的API说明或readme变更说明。
lanhuai 2007-08-17
希望能够提供Solr的解决方案

在Spring中比较好配置,但是在Solr中好像没有类似Spring的<property name="knife" ref="paoding"/>的方式

Qieqie 写道
rainsf 写道

2、最终的Analyer子类(PaodingAnalyzer),应该提供一个无参构造器,因为大多数框架通常都是配置指定Analyer实现类通过反映加载Analyer的,如Hibernate Search.


参见:
JavaEye:Spring Context下使用"庖丁解牛"
或:
Google:Spring Context下使用"庖丁解牛"

简单摘要(以上面两个链接中的说明为准,这里只是摘要):

   <bean id="writerAnalyzer" class="net.paoding.analysis.analyzer.PaodingAnalyzer">
       <property name="knife" ref="paoding"/>
       <property name="mode" value="1"/>
   </bean>

   <bean id="queryAnalyzer" class="net.paoding.analysis.analyzer.PaodingAnalyzer">
       <property name="knife" ref="paoding"/>
       <property name="mode" value="2"/>
   </bean>

   <bean id="paoding" class="net.paoding.analysis.knife.PaodingMaker"  factory-method="make"/>


---------
补:
1、建立索引和使用索引只能使用同一种/模式的分词器
2、2.0.2以后(包含)queryMode和writerMode这两个名称将重构为更好的名称,请留意倒是的API说明或readme变更说明。
linliangyi2007 2007-08-15
恭喜qieqie兄新版发布。
俺地IKAnalyzer新版分词器也在昨天发布了,这里搭个顺风车,咔咔!!
http://download.csdn.net/source/227957
Qieqie 2007-08-14
to yheart:

1、你的改法没有必要。而且这样改也不是良好的。
PaodingAnalyzer具有无参的构造函数,你可以使用无参构造函数,然后通过setKnife,setMode设置这两个值。
你可以参考前回复中给出的Spring配置方法。

2、和Tomcat默认字符无关。你要确认的是:
1)你的页面设置什么字符集?
2)你是否设置了CharacterEncodingFilter过滤器用来对请求和响应设置和页面一致的字符集
(如果是struts2,webwork等从MVC框架上就支持字符集配置的,可以不需要配置CharacterEncodingFilter)

如果你配置的是UTF-8编码的,就必须使用UTF-8编码的字典,同时你的操作系统要是UTF-8编码的(注)
如果你配置的是GBK编码的,就必须使用GBK编码的字典,同时你的操作系统要是GBK编码的(注)

[注]:
2.0.0版本使用操作系统的字符集读取字典,所以要保证你使用的字典和操作系统是同一编码的
如果你使用的页面字符集和操作系统不一样,现在庖丁没有办法配置用页面的字符集读取字典,
作为暂时的做法,你可以直接去将net.paoding.analysis.dictionary.support.filewords.FileWordsReader
中的87行的new InputStreamReader(new FileInputStream(f))改为new InputStreamReader(new FileInputStream(f), "你页面配置的编码")
这些情况会在2.0.x进行改进。上面的一些贴子,已经叙述了这个问题


3、程序抛出的StringIndexOutOfBoundsException异常是因为使用错误的字符集导致的,设置正确了,也就不会有异常。
yheart 2007-08-14
作者您好:我在用“庖丁”做为compass的中文分词(spring+hibernate+compass+tomcat),做了以下修改:

1、由于只能在配置文件中使用无参的构造函数,所以在PaodingAnalyzer 这个类的tokenStream方法中,把
if (knife == null) {
throw new NullPointerException("knife should be set before token");
}
改成了:
if (knife == null) {
knife = PaodingMaker.make(Config.properties());
}

2、由于tomcat默认字符是iso-8859-1,因此在tokenStream方法中,把传入的reader对象读出保存到一个String中,然后转换字符集到utf-8,然后再构造一个StringReader传入返回语句:
return new PaodingTokenizer(new StringReader(str), knife, createTokenCollector());

然后在使用时,抛出java.lang.StringIndexOutOfBoundsException异常,提示CJKKnife 类的 && beaf.charAt(end) >= word.getNext().charAt(count); 处 String index out of range。

不知道此处是存在BUG?还是由于我做的两处修改而导致问题?如果我在这句话前面先加个判断,如果count溢出,则把word.getNext()的值的length-1赋值给 count,不知道这样修改是否会造成其它影响?谢谢~~
youkao 2007-08-12
Qieqie 写道
简繁体方面,庖丁需要有人贡献这些函数:

1、big5->utf-8
2、gbk->utf-8
3、utf-8繁->utf-8简

或者,等价的另一种方式:
4、big5->gbk
5、utf-8->gbk
6、gbk繁->gbk简

第一种方式感官上优于第二种。



这个继续解决中,准备搞台电脑安装繁体版 XP
youkao 2007-08-12
PaodingMaker 在每次加载的时候都会初始化一次,很好损失内存,在WEB下应用会经常内存溢出,建议修改成单例模式,其他保持不变,修改如下:


public class PaodingMaker {

private static Log log = LogFactory.getLog(PaodingMaker.class);

private static Paoding paoding;

private static PaodingMaker instance = null;

public static synchronized PaodingMaker getInstance() {
if (instance == null)
instance = new PaodingMaker();
return instance;
}

public PaodingMaker(){
make();
}

public static Paoding make() {
if (paoding == null) {
synchronized (PaodingMaker.class) {
paoding = make(Config.properties());
}
}
return paoding;
}

// @SuppressWarnings("unchecked")
public static Paoding make(Properties p) {
try {
Paoding paoding = new Paoding();
// 包装各种字典-将自动寻找,若存在则读取类路径中的paoding-analysis.properties文件
// 若不存在该配置文件,则一切使用默认设置,即字典在文件系统当前路径的dic下(非类路径dic下)
Dictionaries dictionaries = new FileDictionaries(p);
Enumeration names = p.propertyNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
// 以paoding.knife.class开头的被认为是knife对象
if (name.startsWith("paoding.knife.class")) {
String className = p.getProperty(name);
Class clazz = Class.forName(className);
Knife knife = (Knife) clazz.newInstance();
if (knife instanceof DictionariesWare) {
((DictionariesWare) knife)
.setDictionaries(dictionaries);
}
// 把刀交给庖丁
System.out.println("add knike: " + className);
log.info("add knike: " + className);
paoding.addKnife(knife);
}
}
return paoding;
} catch (Exception e) {
throw new IllegalStateException("Wrong paoding properties config.",
e);
}
}
}


修改后效率大大提高:
Searching time: 188 毫秒 (第一次加载)
Searching time: 16 毫秒
Searching time: 0 毫秒
Searching time: 15 毫秒
Searching time: 0 毫秒
Searching time: 0 毫秒
Searching time: 0 毫秒
Qieqie 2007-08-12
简繁体方面,庖丁需要有人贡献这些函数:

1、big5->utf-8
2、gbk->utf-8
3、utf-8繁->utf-8简

或者,等价的另一种方式:
4、big5->gbk
5、utf-8->gbk
6、gbk繁->gbk简

第一种方式感官上优于第二种。
Qieqie 2007-08-12
[表述错误-所以删除]
youkao 2007-08-11
在网上找到一个 BIG2GB的类简单的改了下,做了一个包,看 庖丁 需要不,需要的话就加进去!


使用方法

private static String QUERY = "固若金湯";


GB2Big5 pTmp = GB2Big5.getInstance();
String queryString = pTmp.big52gb(QUERY);

QueryParser parser = new QueryParser(FIELD_NAME, PaodingAnalyzer.queryMode(paoding));
Query query = parser.parse(queryString);



这段时间在搞拼音联想(目前有些BUG),过段时间在加入到庖丁 里面去
rainsf 2007-08-10
我终于发现在“高亮错误”的可笑原因,在JDK1.6环境下,直接命令行来运行那几个例子,高亮就没有问题,但我在Eclipse下无论用JDK1.5还是JDK1.6,编译级别无论用5还是6,高亮都一样是错误的,在Tomcat环境下运行情况同样。以上情况看起来很可笑。
真的很郁闷,具体原因出在哪里,还没有时间考究,只知道有这样的事实。切切.王,你也在Eclipse或服务器环境下,或JDK1.5下试试吧,看看情况怎样。。。
心无旁骛 2007-08-10
我已经把paoding在linux下用起来了,对编码问题根本可以视而不见,一样很好用。
windyboy 2007-08-10
我之前吧字典文件强制转成utf-8读取,但发现有错误
后来不得以,修改读取接口,强制使用gbk读取,没有问题
Qieqie 2007-08-10
根据这两天友善的同学们给我的反馈,庖丁暂时收到有这几个方面要求:

1、编译成较低JDK版本的JAR包[目前打的JAR包是JDK6.0的,一部分人应该下载源代码后自己打包成符合自己环境的版本-还好这不是不可解决的]
2、字典的保存和读取强制采用UTF-8编码格式
3、支持运行时修改、添加、删除字典以及字典目录(可配置间隔时间)
4、支持把繁体字的UTF-8编码,等价转化于对应字的简体UTF-8进行,后进行分词(也就不再另外有专门的繁体词典)-是否可行?
5、庖丁不需要去保证能够正确处理非UTF-8编码的文本。对于GBK(GB2312),big5等编码的文本,都应在提交给庖丁之前就已经转为UTF-8编码。
Qieqie 2007-08-09
我委托其他同学试一下"高度错误问题"。他们下载google上提供的 链接 后运行和我一样是正确的。

我在我的本上(xp home JDK1.6)、PC(xp pro JDK1.6)、Server(rhas JDK1.5)三个机器上使用高亮都是OK的,委托帮忙测试的人也都反馈正确,
但是你确实截图上出现高亮到最大词的问题,这也是千真万确的,所以很雾水。

而且如果这个问题为真,也应是代码的问题,应跟操作系统环境无关。

只能多多试验了,然后最后求证,看看差别在什么地方。

----------------------
背景: rainsf说的问题是:
检索“中华”时,在它那边的环境中会把“中华人民共和国”加亮的问题。


希望有热心的同学帮忙一下
下载paoding-analysis-2.0.0.zip解压后,进入cmd命令行,运行一下example.bat如下:
E:\xxx\paoding-analysis-2.0.0>example.bat 中华

看看结果如何,是否<b></b>仅包含在“中华”,还是包含在“中华人民共和国”外面
然后把运行结果COPY发送站内消息给我。 不胜感谢 ~~ orz (我给您趴下了)

[由于本人不慎,打的JAR是JDK6的,所以如果环境不是JDK6的同学,可能不能直接运行example.bat]

这是我的运行结果:

引用

E:\...\paoding-analysis-2.0.0>example.bat 中华

E:\...\paoding-analysis-2.0.0>java -cp ./;paoding-analyis.jar;lib/commons-logging.jar;lib/lucene-core-2.2.0.jar;lib/lucene-highlighter-2.2.0.jar net.paoding.analysis.examples.gettingstarted.ch2.PeopleRepublicOfChina 中华
2007-8-9 21:39:27 net.paoding.analysis.knife.FileWordsLoader setProperties
信息: paoding.dic.home=dic/
2007-8-9 21:39:29 net.paoding.analysis.knife.PaodingMaker make
信息: add knike: net.paoding.analysis.knife.CJKKnife
2007-8-9 21:39:29 net.paoding.analysis.knife.PaodingMaker make
信息: add knike: net.paoding.analysis.knife.NumberKnife
2007-8-9 21:39:29 net.paoding.analysis.knife.PaodingMaker make
信息: add knike: net.paoding.analysis.knife.LetterKnife
Searching for: 中华

<b>中华</b>人民共和国(英文:The People's Republic of China,通常简称...];<b>中
华</b>人民共和国将行政區劃分为23个省、5个少数民族自治区、4个直辖市、以及2个特别
行政区,但台湾不在<b>中华</b>人民共和国政府实际控制范围内(参见:台湾问题)。<b>
中华</b>人民共和国是世界上人口最多的国家,人口总数...多数,其余55个民族被统称为
少数民族。<b>中华</b>人民共和国境内的通用语言是汉语普通话,使用的文字是规范汉字
(此即汉语簡化字),少数民族如壮族、维吾尔族、蒙古族、藏族、朝鲜族等拥有自己的文
字。《<b>中华</b>人民共和国宪法

E:\...\paoding-analysis-2.0.0>
rainsf 2007-08-09
我上面说的是文件储存编码,这个是要解决的,也好解决。
你说的是字符集问题,当然啦,如果用户检索的是繁体字,你的简体词典里又没有这个词,那肯定检索不到结果。我看过有的中文分词做了这方面的工作,里面有三个版本的中文词典。如有需要我可以发给你。

很不好意思,高度错误问题仍然存在,我已经尝试了很多次了。你应该也收到我的截图吧。郁闷,为什么你运行就没有问题呢。是不是你本地还有什么修改没提交?这个问题不解决没法用呀。
Qieqie 2007-08-09
不是这个问题。

我指的是使用者的系统(不是开发者源代码编码,而是用户传过来的字符串编码)不仅仅限制在UTF-8,可能是其他编码。
如果请求传过来的是其他编码形式的文本,而词典不与其匹配,那么词典就没用了。

说到这,激发我想到一个相关的问题:

怎么同时支持不同编码,但实际是同一个字的的分词?

比如同样都是“体育”这个词,GBK有GBK的编码,UTF-8有UTF-8的编码,big5有big5的编码(“體育”)。

对!中文分词应该把这些不同的编码的词视为一个词。
策略上可以以UTF-8作为统一标准,由庖丁自动将非UTF-8的文本(包括正体字/繁体字),转为简体UTF-8的,然后再进行分词!

这个需求应该是有用的。现在庖丁解牛没有做这方面的工作。
Qieqie
搜索本博客
博客分类
最近加入圈子
存档
最新评论