在pyLucene中使用中文分词器(在pyLucene中引用Jar包)
(刚刚解决的一个问题,在中文里面没有搜索到相关内容(英文里其实也没搜到...),发一篇在这里备人索引,关键字:pyLucene, JCC,
Lucene, Importing JAR)
在Lucene里面引用别人写好的中文分词器很简单,加个CLASSPATH就好。但是在pyLucene(JCC版)里,由于python所能够引用
到的Jar包都是用JCC这个编译器(姑且认为是个编译器吧)预先编译了python调用接口的。(反过来说,就是没有经JCC编译的Jar包是休想在
python里面直接访问的)
所以,在pyLucene中使用Jar包形式的中文分词器不得不重新编译。分隔线以下是OSFoundation某热心人关于如何修改Makefile
让Jar包可以和pyLucene打包到一起的回复。
-------------------------------------热心人回复的分隔
线-------------------------------------
Andi Vajda:
To access your class(es) by name from Python, you must have JCC
generate wrappers for it (them). This is what is done line 177 and on
in PyLucene's Makefile. The easiest way for you to add your own Java
classes to PyLucene is to create another jar file with your own
analyzer classes and code and add it to the JCC invocation there.
For example, the Makefile snippet in question currently says:
GENERATE=$(JCC) $(foreach jar,$(JARS),--jar $(jar)) \
--package java.lang java.lang.System \
java.lang.Runtime \
--package java.util \
java.text.SimpleDateFormat \
--package java.io java.io.StringReader \
java.io.InputStreamReader \
java.io.FileInputStream \
--exclude org.apache.lucene.queryParser.Token \
--exclude org.apache.lucene.queryParser.TokenMgrError \
--exclude
org.apache.lucene.queryParser.QueryParserTokenManager \
--exclude org.apache.lucene.queryParser.ParseException \
--python lucene \
--mapping org.apache.lucene.document.Document 'get:(Ljava/
lang/String;)Ljava/lang/String;' \
--mapping java.util.Properties 'getProperty:(Ljava/lang/
String;)Ljava/lang/String;' \
--sequence org.apache.lucene.search.Hits 'length:()I' 'doc:
(I)Lorg/apache/lucene/document/Document;' \
--version $(LUCENE_VER) \
--files $(NUM_FILES)
change the first line to say:
GENERATE=$(JCC) $(foreach jar,$(JARS),--jar $(jar)) --jar myjar.jar \
...
and rebuild PyLucene. That should be all you need to do. Your jar file
is going to be installed along with lucene's in the lucene egg and it
is going to be put on lucene.CLASSPATH which you use with
lucene.initVM().
Your classes can be declared in any Java package you want. Just make
sure that their names don't clash with other Lucene class names that
you also need to use as the class namespace is flattened in PyLucene.
For more information about JCC and its command line args see JCC's
README file at [1].
Andi..
发表者欧兰辉 时间
10:47 上午
pyLucene的自定义Analyzer — 中文分词
昨天决定使用PyLucene做indexer, 主要考虑效率的问题,还有和其他robot配合的问题, 所以放弃了用Zend
Framework中的Lucene做indexer. 大概在网上search了一下.
没有发现具体关于PyLucene的的中文Analyzer的一些资料, 不过还好在PyLucene的Readme.txt中,
对如何做customer analyzer进行描述. 其实很简单 ,
只要在你自定义的Anaylzer中实现一个
tokenStream的方法, 而tokenStream的方法返回的你定义的_tokenStream的object.
然后需要在_tokenStream实现next()方法, next()方法返回的是Token.这样,
你的Analyzer就可以被indexer使用, 并通过next()方法,得到不同Token().
今天抽空把逆向最大匹配的中文分词算法做到一个自定Analyzer里面试一下, 字典先用sogou的.
原文如下:
Technically, the PyLucene programmer is not providing an ‘extension’
but a Python implementation of a set of methods encapsulated by a
Python class whose instances are wrapped by the Java proxies provided
by PyLucene.
For example, the code below, extracted from a PyLucene unit test,
defines a custom analyzer using a custom token stream that returns the
tokens ‘1′, ‘2′, ‘3′, ‘4′, ‘5′ for any document it is called on.
All that is needed in order to provide a custom analyzer in Python is
defining a class that implements a method called ‘tokenStream’. The
presence of the ‘tokenStream’ method is detected by the corresponding
SWIG type handler and the python instance passed in is wrapped by a new
Java PythonAnalyzer instance that extends Lucene’s abstract Analyzer
class.
In other words, SWIG in reverse.
class _analyzer(object):
def tokenStream(self, fieldName, reader):
class _tokenStream(object):
def __init__(self):
self.tokens = ['1', '2', '3', '4', '5']
self.increments = [1, 2, 1, 0, 1]
self.i = 0
def next(self):
if self.i == len(self.tokens):
return None
t = Token(self.tokens[self.i], self.i, self.i)
t.setPositionIncrement(self.increments[self.i])
self.i += 1
return t
return _tokenStream()
analyzer = _analyzer()
store = RAMDirectory()
writer = IndexWriter(store, analyzer, True)
d = Document()
d.add(Field.Text(”field”, “bogus”))
writer.addDocument(d)
writer.optimize()
writer.close()
下
一个项目准备用Python+Django来完成,先做些技术准备。数据库方面用Django已经试验的差不多了,但是似乎性能很差。自己编译了
Mysql,用虚拟机测试,生成1000个用户,1000篇文章用时80秒,这种并发性能恐怕没有办法让人满意。(每篇文章需要单独生成Tag和文章与
Tag的对应关系,涉及8次数据库操作。)花了一天时间试验InnoDB和MyIsam的区别,但是似乎没有影响,开不开Transaction都一样。
先不管它了,也许和我的机器硬件有关系,硬件的sync关不掉。看官方的说法,SlashDot用Django可以实现每秒800条数据的插入速度。
网站肯定要用到全文检索,目前唯一的全文检索解决方案就是Lucene了,.Net上也有Lucene.Net可以选。搜索了一下,发现了PyLucene,这个Python上的Lucene实现。似乎是使用Python对Lucene进行了一次重新包装。
下
载了它的Windows版本,安装比较简单,直接把几个库文件复制到对应的Lib目录就行了。运行了一下Sample目录下的测试文件,先是用
IndexFiles和SearchFiles试了一下,SearchFiles是接收参数来搜索的,但是我没有办法输入中文,会出现错误提示。后来把要
搜索的词直接放到文件里面去,不报错了,但是搜索不出来。本以为PyLucene不支持中文,正在纳闷豆瓣的搜索是怎么做的,突然发现了一个好东西。
看
了一下sample目录下的LuceneInAction目录,里面居然有个ChineseTest文件。它调用的是另一个目录下的测试文件,测试一个汉
字的搜索,运行了一下,居然是成功的。再看了一下IndexFiles,里面读文件用的编码是英文编码,改成GB2312,OK,可以搜索到了。但是只能
搜索单字,不能按词搜索。只要输入两个字就出错。再比较一下Test文件,Query的生成方法不一样,TermQuery似乎是单元搜索,不支持词搜
索,换成了QueryParser,成功了。但是还有一个小问题,比如搜索“中华”,在文章里,在中和华中间随便加多少空格和回车都没有关系,照样可以搜
索到。但是加入其它字或者英文字母以后就搜索不到了。这个影响不大,毕竟人们常用的搜索都是自然词。
有了PyLucene这个好东西,心头一块大石头算是落地了。没想到,等到要在开发服务器的Linux上安装这个东西的时候,可费了功夫了。
官
方的下载包做的很奇怪,ubuntu, debian,
gentoo都有对应的二进制包可用,但是Redhat就没有,只能用源码包编译,而它的编译方式又做的极其简陋,没有configure文件,只有
Makefile。按照说明,需要自己编辑Makefile,去掉你需要的注释行,修改参数,然后直接Make。但是里面有一个对DB的引用,检查了一
下,BerkeleyDB似乎在CentOS4里面没有,只好自己去官方网站下载了4.4.20的源码,先编译安装它。虽然最新版是4.5.20,但是怕
不兼容,所以还是用它配置文件里推荐的这个。编译这个东西也挺奇怪,不过还好,毕竟有官方文档一步步的说明,解压后需要进入build_unix目录,然
后调用../dist/configure来配置,然后make && make
install。指定prefix失败。装完了这个东西,再改PyLucene的配置文件,根据生成的错误消息猜了好几次才终于可以编译了。最终需要改的
地方为:
1、取消Linux那一段的注释。
2、PREFIX_PYTHON是你的Python的目录。因为我的Python是自己编译安装的,所以这里需要改一下。
3、DB=这个我指向了BerkeleyDB的源码目录才通过编译的(还好没删)。
其
它的不用改。编译到一半报错,有一个libgcj.a文件找不到,到/usr/lib下找了一下没有这个文件,但是有个差不多的.so,于是做了个ln
-s,居然就通过编译了。然后make
install的时候又有问题,提示libgcc_s.so.1找不到,这个是Makefile里面的LIB_INSTALL参数指定的,我不知道它的意
义在哪里,最后我也没找到这个文件,但是直接进入Sample目录运行了一下测试文件,居然就成功了。真TMD。这就是Linux吗?
终于可以安心的研究Django了。似乎Ruby On Rails还没有支持中文全文检索的模块吧?
Feedback
#1楼 58.37.222.*
回复 引用
2006-12-21 23:21 by vik [未注册用户]
呵呵,我也正打算做类似的东西。
django+pylucene。
这总非纯python的东西跨起平台来还是有些麻烦。
lupy是纯python的lucene,moinmon用的就是这东东。
如果pylucene搞不定就用这个。
#2楼 221.217.208.*
回复 引用
2007-02-23 22:46 by ant [未注册用户]
我也遇到了这个问题,不过改了chinesetest.py和indexfiles的编码仍然出错,
提示:InvalidArgsError: (, '__init__', ('contents', '\xb5\xc0'))
你能把代码贴上来吗?非常感谢了!
----------------------------------
看
了一下sample目录下的LuceneInAction目录,里面居然有个ChineseTest文件。它调用的是另一个目录下的测试文件,测试一个汉
字的搜索,运行了一下,居然是成功的。再看了一下IndexFiles,里面读文件用的编码是英文编码,改成GB2312,OK,可以搜索到了。但是只能
搜索单字,不能按词搜索。只要输入两个字就出错。再比较一下Test文件,Query的生成方法不一样,TermQuery似乎是单元搜索,不支持词搜
索,换成了QueryParser,成功了。但是还有一个小问题,比如搜索“中华”,在文章里,在中和华中间随便加多少空格和回车都没有关系,照样可以搜
索到。但是加入其它字或者英文字母以后就搜索不到了。这个影响不大,毕竟人们常用的搜索都是自然词。
#3楼 125.122.86.*
回复 引用
2008-04-17 23:39 by ajkoo [未注册用户]
我遇到一个很奇怪的问题,我用gcj安装的PyLucene,系统是redhat ,我在命令行下 import PyLucene 就没有任何问题,但是应用到django的项目中就有问题了,显示500..
具体问题查看日志只有Premature end of script headers: dispatch.fcgi
不知道是虾米问题。。。