Google

星期日, 六月 29, 2008

Precision Graphics Markup Language (PGML)

This version:
http://www.w3.org/TR/1998/NOTE-PGML-19980410
Latest version:
http://www.w3.org/TR/1998/NOTE-PGML
Authors:
Nabeel Al-Shamma, Adobe Systems Incorporated
Robert Ayers, Adobe Systems Incorporated
Richard Cohn, Adobe Systems Incorporated
Jon Ferraiolo, Adobe Systems Incorporated
Martin Newell, Adobe Systems Incorporated
Roger K. de Bry, International Business Machines Corporation
Kevin McCluskey, Netscape Communications Corporation
Jerry Evans, Sun Microsystems, Inc.
Copyright 1998 Adobe Systems Incorporated. All rights reserved.
http://www.w3.org/TR/1998/NOTE-PGML-19980410
非常重要的东西。

标签:

星期四, 六月 26, 2008

[Python]用 Python 实现的线程池

为了提高程序的效率,经常要用到多线程,尤其是IO等需要等待外部响应的部分。线程的创建、销毁和调度本身是有代价的,如果一个线程的任务相对简 单,那这些时间和空间开销就不容忽视了,此时用线程池就是更好的选择,即创建一些线程然后反复利用它们,而不是在完成单个任务后就结束。

下面是用Python实现的通用的线程池代码:

  1. import Queue, threading, sys
  2. from threading import Thread
  3. import time,urllib
  4. # working thread
  5. class Worker(Thread):
  6. worker_count = 0
  7. def __init__( self, workQueue, resultQueue, timeout = 0, **kwds):
  8. Thread.__init__( self, **kwds )
  9. self.id = Worker.worker_count
  10. Worker.worker_count += 1
  11. self.setDaemon( True )
  12. self.workQueue = workQueue
  13. self.resultQueue = resultQueue
  14. self.timeout = timeout
  15. def run( self ):
  16. ''' the get-some-work, do-some-work main loop of worker threads '''
  17. while True:
  18. try:
  19. callable, args, kwds = self.workQueue.get(timeout=self.timeout)
  20. res = callable(*args, **kwds)
  21. print "worker[%2d]: %s" % (self.id, str(res) )
  22. self.resultQueue.put( res )
  23. except Queue.Empty:
  24. break
  25. except :
  26. print 'worker[%2d]' % self.id, sys.exc_info()[:2]
  27. class WorkerManager:
  28. def __init__( self, num_of_workers=10, timeout = 1):
  29. self.workQueue = Queue.Queue()
  30. self.resultQueue = Queue.Queue()
  31. self.workers = []
  32. self.timeout = timeout
  33. self._recruitThreads( num_of_workers )
  34. def _recruitThreads( self, num_of_workers ):
  35. for i in range( num_of_workers ):
  36. worker = Worker( self.workQueue, self.resultQueue, self.timeout )
  37. self.workers.append(worker)
  38. def start(self):
  39. for w in self.workers:
  40. w.start()
  41. def wait_for_complete( self):
  42. # ...then, wait for each of them to terminate:
  43. while len(self.workers):
  44. worker = self.workers.pop()
  45. worker.join( )
  46. if worker.isAlive() and not self.workQueue.empty():
  47. self.workers.append( worker )
  48. print "All jobs are are completed."
  49. def add_job( self, callable, *args, **kwds ):
  50. self.workQueue.put( (callable, args, kwds) )
  51. def get_result( self, *args, **kwds ):
  52. return self.resultQueue.get( *args, **kwds )

Worker类是一个工作线程,不断地从workQueue队列中获取需要执行的任务,执行之,并将结果写入到resultQueue中,这里的 workQueue和resultQueue都是现成安全的,其内部对各个线程的操作做了互斥。当从workQueue中获取任务超时,则线程结束。

WorkerManager负责初始化Worker线程,提供将任务加入队列和获取结果的接口,并能等待所有任务完成。

一个典型的测试例子如下,它用10个线程去下载一个固定页面的内容,实际应用时应该是执行不同的任务。

  1. def test_job(id, sleep = 0.001 ):
  2. try:
  3. urllib.urlopen('https://www.gmail.com/').read()
  4. except:
  5. print '[%4d]' % id, sys.exc_info()[:2]
  6. return id
  7. def test():
  8. import socket
  9. socket.setdefaulttimeout(10)
  10. print 'start testing'
  11. wm = WorkerManager(10)
  12. for i in range(500):
  13. wm.add_job( test_job, i, i*0.001 )
  14. wm.start()
  15. wm.wait_for_complete()
  16. print 'end testing'

完成的程序可以在这里下载

http://blogger.org.cn/blog/more.asp?name=lhwork&id=22262

标签: ,

星期五, 六月 20, 2008

如何使用wxPython设计gui

wxPython介绍+一个实用的例子

1. wxPython简介

wxPython是wxWidget的库的一个python的封装。提供了一些库和一些工具。

这样wxPython即有python语言的优点:
语法强悍,少写了不少代码:)

也有wxWidget图形库的优点:
直接拉控件到大概位置就行了,不需要去调整控件的对齐,也不需要关心gui界面是否支持各种分辨率的桌面。而且界面都是可以运行时切换,只要写很少的切换代码。跨平台的图形库...

后悔,我怎么以前会用vb开发gui的 -_-!。

缺点,网上资料还比较少。而且在线文档都是英文的。不过如果英文好的话,到真的无所谓,因为wxPython的安装包本身提供的工具和资料也足够多,足够好了。

2. 开发入门
我使用ultraedit作为编辑器,wxPython自带的XRCed作为编辑xrc文件(一种xml格式的资源文件,类似于VC6中的RC文件)。

文档主要参考wxPython自带的在线文档和demo代码。不过关于如何使用xrc文件设计gui,wxPython自带的资料似乎还不够详细,这也是我写本文的原因。

通常情况下google"cvs def wxpython相关的关键字"可以快速找到开源的源代码参考。

如果这些例子还不够的话,就参考我的程序吧,这是一个商用程序的原型,我相信该程序的内容已经足够丰富了,应该比网上的一些wxPython教程中的hello world程序更有借鉴意义。

3. 源代码
两个文件,main.py是主程序,main.xrc是资源文件。只要安装了了python和wxpython,然后将这两个文件放在同一个目录中,运行main.py就可以了。

http://www.builder.com.cn/2008/0527/887121.shtml

很重要,此文的实现基于.xrc文件。

标签: , ,

wxpython:sizer学习

使用sizer后,mainFrame的大小由sizer的孩子决定

grid sizer:

最简单的一个种sizer,各个栅的大小相同,栅的最大大小取决以栅中最大孩子的尺寸(当一个sizer被创建时,它根据它的孩子的综合的最小尺寸(最小的宽度和最小的高度)隐含地创建一个最小尺寸。),如果一个栅没有孩子,不会占有效空间的.gridsizer不会限制孩子的个数的,即使在开始声明也是一样

=========================

flex grid sizer

默认情况下,当尺寸调整时,它不改变它的单元格的尺寸。

可以指定某方向上的行为(以行或列为其它单位,gridsizer是以整体为单位),每个栅的宽度是该列中宽度最大的项目的宽度,它们的高度是该行中宽度最高的项目的宽度。显式地告诉该sizer该行或列是可扩展的:

当窗体大小变化时,需要显式地告诉该sizer该行或列是可扩展的:
AddGrowableCol(idx, proportion=0)
AddGrowableRow(idx, proportion=0)

SetFlexibleDirection(direction)

SetNonFlexibleGrowMode(mode)

=========================
grid bag sizer

1、能够将一个窗口部件添加到一个特定的单元格。(如果一个栅没有孩子,会占有效空间的)
2、能够使一个窗口部件跨越几个单元格(就像HTML表单中的表格所能做的一样)。

注意这里的Add()方法与以前的看起来有点不同 :

1 Add(window, pos, span=wx.DefaultSpan, flag=0, border=0, userData=None)

2 Add(sizer, pos, span=wx.DefaultSpan, flag=0, border=0, userData=None)

3 Add(size, pos, span=wx.DefaultSpan, flag=0, border=0, userData=None)

4 AddItem(item)
比其它sizer多了一个位置参数:因为它为孩子预留了空间

============== 下面是通用方法 ================

sizer对象的构造方法有两个比较重要的参数:

flag:窗体风格,对齐方式,边框位置

proportion:如果使用窗体大小变化时的空间使用,为一个比例值

孩子指定一个最小的尺寸

窗口的方法

SetMinSize(width, height)

SetSizeHints(minW, minH, maxW, maxH)

使用sizer的SetItemMinSize()方法。它也有三个形式:

SetItemMinSize(window, size)
SetItemMinSize(sizer, size)
SetItemMinSize(index, size)

对sizer添加或移除孩子:

Add(window, proportion=0, flag=0, border=0, userData=None)
Add(sizer, proportion=0, flag=0, border=0, userData=None)
Add(size, proportion=0, flag=0, border=0, userData=None)

Insert(index, window, proportion=0, flag=0, border=0, userData=None)
Insert(index, sizer, proportion=0, flag=0, border=0, userData=None)
Insert(index, size, proportion=0, flag=0, border=0, userData=None)

Prepend(window, proportion=0, flag=0, border=0, userData=None)
Prepend(sizer, proportion=0, flag=0, border=0, userData=None)
Prepend(size, proportion=0, flag=0, border=0, userData=None)

Detach(window)
Detach(sizer)
Detach(index)

管理它的孩子的尺寸和对齐的

调整grid sizer的大小时,每个部件之间的间隙将随之改变,但是默认情况下,窗口部件的尺寸不会变,并且始终按左上角依次排列

添加一个窗口部件到sizer时,可以通过给flag参数一个特定值来调整该窗口部件的尺寸改变行为。
wx.ALIGN_BOTTOM:按照窗口部件被分配的空间(格子)的底部对齐。

wx.ALIGN_CENTER:放置窗口部件,使窗口部件的中心处于其所分配的空间的中心。

wx.ALIGN_CENTER_HORIZONTAL:在它所处的格子中,水平居中。

wx.ALIGN_CENTER_VERTICAL :在它所处的格子中,垂直居中。

wx.ALIGN_LEFT:靠着它所处的格子左边缘。这是默认行为。

wx.ALIGN_TOP:靠着它所处的格子的上边缘。这是默认的行为。

wx.EXPAND:填满它所处的格子空间。

wx.FIXED_MINSIZE:保持固定项的最小尺寸。

wx.GROW:与wx.EXPAND相同。但比之少两个字符,节约了时间。

wx.SHAPED:窗口部件的尺寸改变时,只在一个方向上填满格子,另一个方向上按窗口部件原先的形状尺寸的比列填充。什么方向的sizer就向什么方向增长

管理每个孩子的边框

边框是连续数量的空白空间,方向有:wx.BOTTOM, wx.LEFT, wx.RIGHT, wx.TOP

传递了边框信息到flags参数后,也需要传递边框宽度的像素值给border参数 ,为边框的大小

http://sellroad.w58.ws86.com/jessinio/?p=512

标签: , , ,

Python中向MySQL保存Blob

Python code
import MySQLdb, cPickle
# Connect to a DB, e.g., the test DB on your localhost, and get a cursor
connection = MySQLdb.connect(db="test")
cursor
= connection.cursor( )
# Make a new table for experimentation
cursor.execute("CREATE TABLE justatest (name TEXT, ablob BLOB)")
try:
# Prepare some BLOBs to insert in the table
names = 'aramis', 'athos', 'porthos'
data
= { }
for name in names:
datum
= list(name)
datum.sort( )
data[name]
= cPickle.dumps(datum, 2)
# Perform the insertions
sql = "INSERT INTO justatest VALUES(%s, %s)"
for name in names:
cursor.execute(sql, (name, MySQLdb.escape_string(data[name])) )
# Recover the data so you can check back
sql = "SELECT name, ablob FROM justatest ORDER BY name"
cursor.execute(sql)
for name, blob in cursor.fetchall( ):
print name, cPickle.loads(blob), cPickle.loads(data[name])
finally:
# Done. Remove the table and close the connection.
cursor.execute("DROP TABLE justatest")
connection.close( )
http://topic.csdn.net/u/20080319/11/814acdd6-a064-4419-ae52-930cdc97ca45.html

标签: , ,

A PYTHON APPLICATION WHERE THREADS WOULD HELP

Let's say that you want to check the availability of many computers on a network ... you'll use ping. But there's a problem - if you "ping" a host that's not running it takes a while to timeout, so that when you check through a whole lot of systems that aren't responding - the very time a quick response is probably needed - it can take an age.

Here's a Python program that "ping"s 10 hosts in sequence.

import os
import re
import time
import sys

lifeline = re.compile(r"(\d) received")
report = ("No response","Partial Response","Alive")

print time.ctime()

for host in range(60,70):
ip = "192.168.200."+str(host)
pingaling = os.popen("ping -q -c2 "+ip,"r")
print "Testing ",ip,
sys.stdout.flush()
while 1:
line = pingaling.readline()
if not line: break
igot = re.findall(lifeline,line)
if igot:
print report[int(igot[0])]

print time.ctime()

Running that program, it works but it's a bit slow:

[trainee@buttercup trainee]$ python alive
Mon May 9 05:22:51 2005
Testing 192.168.200.60 No response
Testing 192.168.200.61 No response
Testing 192.168.200.62 No response
Testing 192.168.200.63 No response
Testing 192.168.200.64 No response
Testing 192.168.200.65 No response
Testing 192.168.200.66 Alive
Testing 192.168.200.67 No response
Testing 192.168.200.68 No response
Testing 192.168.200.69 No response
Mon May 9 05:23:19 2005
[trainee@buttercup trainee]$

That was 28 seconds - in other words, an extra 3 seconds per unavailable host.

THE SAME APPLICATION, WRITTEN USING PYTHON THREADS

I'll write the application and test it first ... then add a few notes at the bottom.

import os
import re
import time
import sys
from threading import Thread

class testit(Thread):
def __init__ (self,ip):
Thread.__init__(self)
self.ip = ip
self.status = -1
def run(self):
pingaling = os.popen("ping -q -c2 "+self.ip,"r")
while 1:
line = pingaling.readline()
if not line: break
igot = re.findall(testit.lifeline,line)
if igot:
self.status = int(igot[0])

testit.lifeline = re.compile(r"(\d) received")
report = ("No response","Partial Response","Alive")

print time.ctime()

pinglist = []

for host in range(60,70):
ip = "192.168.200."+str(host)
current = testit(ip)
pinglist.append(current)
current.start()

for pingle in pinglist:
pingle.join()
print "Status from ",pingle.ip,"is",report[pingle.status]

print time.ctime()

And running:

[trainee@buttercup trainee]$ python kicking
Mon May 9 05:23:36 2005
Status from 192.168.200.60 is No response
Status from 192.168.200.61 is No response
Status from 192.168.200.62 is No response
Status from 192.168.200.63 is No response
Status from 192.168.200.64 is No response
Status from 192.168.200.65 is No response
Status from 192.168.200.66 is Alive
Status from 192.168.200.67 is No response
Status from 192.168.200.68 is No response
Status from 192.168.200.69 is No response
Mon May 9 05:23:39 2005
[trainee@buttercup trainee]$

3 seconds - much more acceptable than the 28 seconds that we got when we pinged the hosts one by one and waited on each.

http://www.wellho.net/solutions/python-python-threads-a-first-example.html

标签: ,

python中的编码转换

ASCII 是一种字符集,包括大小写的英文字母、数字、控制字符等,它用一个字节表示,范围是 0-127

Unicode分为UTF-8和UTF-16。UTF-8变长度的,最多 6 个字节,小于 127 的字符用一个字节表示,与 ASCII 字符集的结果一样,ASCII 编码下的英语文本不需要修改就可以当作 UTF-8 编码进行处理。

Python 从 2.2 开始支持 Unicode ,函数 decode( char_set )可以实现 其它编码到 Unicode 的转换函数 encode( char_set )实现 Unicode 到其它编码方式的转换

比如 ("你好").decode( "GB2312") 将得到 u'\u4f60\u597d',即 "你"和“好"的 Unicode 码分别是 0x4f60 和 0x597d
再用 (u'\u4f60\u597d').encode("UTF-8") 将得到 '\xe4\xbd\xa0\xe5\xa5\xbd',它是 “你好”的UTF-8编码结果。


python中使用 unicode的关键:unicode是一个类,函数unicode(str,"utf8")从utf8编码(当然也可以是别的编码)的字符串str生成 unicode类的对象,而函数unc.encode("utf8")将unicode类的对象unc转换为(编码为)utf8编码(当然也可以是别的编码)的字符串。于是,编写unicode相关程序,需要做的事情是

* 获取数据(字符串)时,用unicode(str, "utf8")生成unicode对象
* 在程序中仅使用unicode对象,对程序中出现的字符串常量都以u"字符串"的形式书写
* 输出时,可将unicode对象转换为任意编码输出,使用str.encode("some_encoding")

>>> unicode("你好", "utf8")
u'\u4f60\u597d'
>>> x = _
>>> type(x)

>>> type("你好")

>>> x.encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> x.encode("gbk")
'\xc4\xe3\xba\xc3'
>>> x.encode("gb2312")
'\xc4\xe3\xba\xc3'
>>> print x
你好
>>> print x.encode("utf8")
你好
>>> print x.encode("gbk")
???

以上是测试结果(Ubuntu 6.06,locale为utf8),注意type(x)和type("你好")的区别。从编码上可以看出utf8编码与gbk不同。在utf8的 locale设置下,打印x按该环境变量编码(我猜我猜我猜猜猜),而打印x.encode("gbk")则是乱码。
http://guanjh.javaeye.com/blog/131185

标签: , , ,

星期五, 六月 13, 2008

无题

白首相知犹按剑。朱门早达笑谈冠。

人与人之间是这样的吗?

Python扩展方法及工具比较

一、普通扩展方法
扩展Python包括三个步骤:
1. 创建源程序(C, C++, java, ...);
2. 为源程序写wrap代码;
包括四个步骤:
Ø include "Python.h";
Ø 为每个模块函数写wrap,即:PyObject* Module_func();
Ø 为每个模块函数写函数定义,即:PyMethodDef ModuleMethods[]对应表;
Ø 写模块的初始化函数:void initModule()部分。
3. 编译连接;
有两种方法:
(1)使用distutils包。步骤如下:
Ø 修改distutils包中的setup.py文件;
Ø 根据需要运行$ python setup.py build或$ python setup.py install命令,生成扩展
模块的共享库文件。
(2)直接使用gcc命令将模块编译成共享库。命令如下:
$ gcc -fpic -c -I/usr/include/python2.2 -I/usr/lib/python2.2/config foo.c
wrap_foo.c
$ gcc -shared -o foo.so foo.o wrap_foo.o
这样便生成了python可用的foo模块。
4. 使用扩展内容
进入python环境,通过import foo,使用foo模块中的函数。如用foo.func()调用foo模
块中的func()函数。

http://hi.baidu.com/minyuanyang/blog/item/1222c5c831075a137e3e6f0a.html

标签: ,

星期二, 六月 10, 2008

vim多文件编辑

总想写点东西,以证明自己的存在给将来。
1 screen
a 通过ports安装screen
b $screen
c $vi file1.c
d CTRL+a c (表示同时按住CTRL和a,松开后再单击c,以下同)新建一个窗口
e $vi file2.c
f 光标移动到起始点
g CTRL+a [进入copy模式
h 单击空格标志起始点
i 通过hjkl选择范围
j 单击空格标志结束点
k CTRL+a p进入上一窗口
l 单击i进入insert模式
m CTRL+a ]插入当前位置
2 插入
a $vi file1.c
b 移动光标至插入点
c :r file2.c
适合把一个文件插入另一个文件的情况
3 window
a $vi file1.c
b :split file2.c
c CTRL+w j/k在上下窗口切换
可以在您的~/.vimrc中加入如下2行:
map j
map k
这样可以通过CTRL+j/k在上下窗口切换
也可以用如下2行:
map j_
map k_
实现CTRL+j/k切换窗口并使当前窗口占满屏幕
4 buffer
a 通过vim打开多个文件(可以通过ctags或者cscope)
b :ls查看当前打开的buffer(文件)
c :b num切换文件(其中num为buffer list中的编号)
可以用到的命令有
:bn -- next buffer in the buffer list
:bp -- previous buffer in the buffer list
:b# -- previous buffer you was in
可以在您的~/.vimrc中加入如下3行:
map :bn
map :bp
map :b#
实现左右方向键切换到上或下一个buffer,按空格在两个buffer间切换
典型的应用场景是:同时打开c文件和h文件,然后用空格切换
5 mark
a $vi file1.c
b 移动光标至您关注的位置,单击mR
c :e file2.c
d 移动光标至您关注的位置,单击mW
e 然后就可以通过'R/'W在文件间切换
m[a-z]: lowercase marks, valid within one file
m[A-Z]: uppercase marks, also called file marks, valid between files
该方法很适合阅读源码和3个以上文件编辑的情况
方法3,4,5,因为都在同一个vim中,您可以使用yy,yw,y'a,dd,dw,d'a等和p实现copy和粘贴
另外,当您离开一个已修改但未保存的文件时,vim会提示您保存,可以通过如下命令
:set autowrite
实现让其自动保存。
http://blog.chinaunix.net/u1/41770/showart_324555.html

标签: , ,

星期五, 六月 06, 2008

Compiling Python Code

Python source code is automatically compiled into Python byte code by the CPython interpreter. Compiled code is usually stored in PYC (or PYO) files, and is regenerated when the source is updated, or when otherwise necessary.

To distribute a program to people who already have Python installed, you can ship either the PY files or the PYC files. In recent versions, you can also create a ZIP archive containing PY or PYC files, and use a small “bootstrap script” to add that ZIP archive to the path.

To “compile” a Python program into an executable, use a bundling tool, such as Gordon McMillan’s installer (alternative download) (cross-platform), Thomas Heller’s py2exe (Windows), Anthony Tuininga’s cx_Freeze (cross-platform), or Bob Ippolito’s py2app (Mac). These tools puts your modules and data files in some kind of archive file, and creates an executable that automatically sets things up so that modules are imported from that archive. Some tools can embed the archive in the executable itself.

If all you need is to wrap up a couple of Python scripts and modules into a single file, Squeeze might be what you need. For Windows, my ExeMaker tool can also be quite useful (on its own, or in combination with squeeze).

Compiling Python modules to byte code #

Python automatically compiles Python source code when you import a module, so the easiest way to create a PYC file is to import it. If you have a module mymodule.py, just do:

>>> import mymodule

to create a mymodule.pyc file in the same directory. A drawback is that it doesn’t only compile the module, it also executes it, which may not be what you want. (however, it does compile the entire script even if it fails to execute the script).

To do this programmatically, and without executing the code, you can use the py_compile module:

import py_compile

py_compile.compile("mymodule.py")

There’s also a compileall module which can be used to compile all modules in an entire directory tree.

import compileall

compileall.compile_dir("mylib", force=1)

More on byte code #

Python’s byte code is portable between platforms, but not necessarily between Python releases. The imp.get_magic() function returns a 4-byte string identifying the byte code format used by the current interpreter.

You can use the compile function and the marshal module to compile Python code into code objects, and convert such code objects to binary strings. To reverse this process, use marshal to convert from strings to code, and use exec to execute code.

Examples to be added.

http://effbot.org/zone/python-compile.htm

标签:

星期二, 六月 03, 2008

Eclipse RIA工具取得突破性进展

作者 Rob Thornton译者 霍泰稳 发布于 2007年3月26日 上午10时18分

社区
Java
主题
RIA
标签
Eclipse Ajax工具框架,
Eclipse,
Eclipse富Ajax平台
Eclipse 基金会日前宣布了两个旨在提高富互联网应用(RIA,Rich Internet Application)开发的项目里程碑,一是 Eclipse 富Ajax平台(RAP,Rich Ajax Platform)开始支持 JFace 对话框,另外 Eclipse Ajax 工具框架(ATF,Ajax Toolkit Framework)可以支持OS X。

RAP 项目和 Google 的 GWT(Google Web Toolkit)很类似,但是有两点不同,一是 GWT 是在浏览器的一个仿真 Java 引擎上运行,而RAP 主要是在服务端运行,使用 Ajax 更新客户端。在 RAP中 事件处理(Event-handling)的结果是在服务端操作,而在 GWT 中是在客户端。第二,因为是服务器端的,RAP 可以在一个 Web 容器里访问所有的 Java API(Application Programming Interface)和 OSGi(Open Service Gateway Initiative)。RAP 现在被描述为面向Web 应用的一种 Eclipse 富客户端平台(RCP,Rich Client Platform)方法。RAP 现在既支持对话框,也支持事件处理

ATF 项目存在的目的是方便 JavaScript 开发(允许在 Eclipse 内部调试),尤其是通过 IDE 的构建提供 Ajax 运行时产品(Dojo、Zimbra等)。
通 过 ATF,开发人员可以方便地构建、调试和部署他们的 Ajax 应用。它包括很多组件,如一个支持本地和网络文件调试的 JavaScript 调试器和检测 Ajax 应用运行的工具。Eclipse ATF 支持许多当前流行的 Ajax 框架,如 Dojo、Rico和 Zimbra 等。
在 Nexaweb 和 Genuitec 产品中已经应用了 ATF。Wayne Beaton 已经写了一些关于这个项目的使用文章

http://www.infoq.com/cn/news/2007/03/eclipse-atf-rap

标签: , , , , , , , ,

Eclipse开发Laszlo的环境搭建。。。(Link方式)

先抱怨一下,为虾米会坐在“疯狗”的旁边啊,冷的我瘦弱的身躯不住的打颤……

搞了一个上午,虽然其中的过程充满了饥寒交迫、胆战心惊,但是每次遇到困难的时候,耳边就会响起毛主席的指示:勒紧裤腰带,为了新中国,一定要把原子弹搞 出来。想到这里就精神倍增,最终克服了重重困难(包括瞌睡虫的入侵),几经波折,把“它”搞掂了。成功的喜悦是无法用言语表达的,我真想从10楼跳下去 啊……

从小老师就教育:公欲善其事,必先利其器。所以,之前的准备工作是必不可少的。

首先,一些基本的准备工作要做好。准备工作包括两个部分,“手艺”和“材料”。手艺就是在Eclipse里面使用link方式安装插件,要是还没有拜师学会的话,可以先看看这里 Eclipse基础--使用links方式安装Eclipse插件

“材料”需要(以下材料缺一不可):
1、Eclipse-3.01 这个必不可少啊,没有这东西就跟没有电脑一样,别干算了……
2、openlaszlo-3.0.2 这个是Laszlo服务器
下载地址: http://www.openlaszlo.org/download/binaries/3.0.2/openlaszlo-3.0.2-windows-dev-install.exe
3、laszloIDE(IBM未告诉我版本) 这个是开发lzx for Eclipse的插件,由IBM开发,不算太难用,一般难用,莫办法啊……
下载地址: http://alphaworks.ibm.com/tech/ide4laszlo/download (注册用户才能下载)
4、EMF SDK 2.0.1 (EMF + SDO + XSD) 不晓得干啥子用的,只晓得要,时间有限,不去研究它了。
下载地址: http://eclipse.org/downloads/download.php?file=%2Ftools%2Femf%2Fdownloads%2Fdrops%2F2.0.1%2FR200409171617%2Femf-sdo-xsd-SDK-2.0.1.zip
5、GEF 3.0.1 Graphical Editing Framework
下载地址: http://download.eclipse.org/tools/gef/downloads/drops/R-3.0.1-200408311615/GEF-SDK-3.0.1.zip
6、org.openlaszlo.tools 这个东西折磨了我好久,不知道干什么用的,laszloIDE的说明上也没有要,但是就是要。
文件一下载地址: http://www.openlaszlo.org/eclipse/update/laszlo/features/org.openlaszlo.tools_3.0.0.jar
文件二下载地址: http://www.openlaszlo.org/eclipse/update/laszlo/plugins/org.openlaszlo.tools_3.0.0.jar
两个文件都要下载,下载以后用winrar解压缩,然后自己手动添加到目录内,目录需要自己建立。如下图所示:

(注:原图无法加载)


需要注意的是:plugins 和 features 目录下所包含的应该是目录,而不是jar文件。至少我摸索的结果是这样,默认的下载以后是.jar文件,怎么都不行,解压缩以后就可以了。看看有没有更好的解决方法。

第二步,安装。
所谓万事具备,只欠东风,所有的东西都准备好了,OK,就进入了安装环节。
1、安装eclipse,其实只需要解压缩就可以了。然后安装语言包。所有过程都很简单,略过好了。
2、安装laszlo,也很容易,继续略过……
3、将所有插件放到一个文件夹下面,当然也可以不用,但是东丢一个西丢一个总不是件好事情。假如都是放在了D:\myplugin 下面。
4、在安装的eclipse的目录下(假如是安装在D盘,目录就是d:\eclipse),新建一个links的目录,然后在里面新建这几个文件:
(1)laszloEclipse.link (2)gef.link (3)emf.link (4)laszloIDE.link
内容分别为(括号及括号内数字不要,直接path开头):
(1)path=D:/myplugin/laszloEclipse
(2)path=D:/myplugin/gef
(3)path=D:/myplugin/emf
(4)path=D:/myplugin/laszloIDE
注意目录是用反斜杠"/"区分。
到这里,安装过程结束了,剩下的就是配置过程了。

第三步,配置。
关掉打开着的eclipse,然后再打开……好像重新启动总是很讨厌,但是莫办法啊,free高于一切……
点击 窗口|首选项 看看有没有如图这样一个“laszlo”的选单啊,如果没有,赶紧看看前面哪里弄错了。

(注:原图无法加载)

设置好laszlo服务器的根目录和端口,应用就可以了。

所有软件可以在这里下载:http://blog.gxsti.net/download/laszlo/myplugin.rar
http://blog.gxsti.net/download/laszlo/links.rar

第四步,跳楼。
启动laszlo服务器,打开eclipse,新建一个lzx文件试试,看看能不能预览……反正我是成功了,呵呵。要不行的话检查一下所有这些软件的版本和设置。
http://www.disound.com/zblog/post/72.html

标签: , ,

php+xapian extension的安装

xapian是啥玩意?

xapian 是一个“Xapian 是一个开源概率论信息检索库,基于GPL发布。它是用C++编写的,提供的绑定可以支持其它语言(支持Perl, Python, PHP, Java, and TCL )的开发。 Xapian 设计为一个高度可适应的工具集,可以让开发人员方便地为他们自己的应用程序增加高级索引和搜索功能。”

在网上找到这段介绍后,俺手痒痒就想试试xapian —- 一定要给php整个这东东上去.参考了若干文档以后,这就开始动手了(我的环境仍然是freebsd + apache 2.2 + php 5.1.2,apache和php原来就已经安装好):

1.下载xapian

cd /usr/local/src
wget http://www.oligarchy.co.uk/xapian/0.9.4/xapian-core-0.9.4.tar.gz
wget http://www.oligarchy.co.uk/xapian/0.9.4/xapian-bindings-0.9.4.tar.gz

前者是xapian的核心lib代码,后者是给其它语言调用的接口

2.安装Xapian-core

cd /usr/local/src
tar xzvf xapian-core-0.9.4.tar.gz
cd xapian-core-0.9.4
./configure –prefix=/usr/local/xapian
make
make install

3.安装Xapian-bindings

cd /usr/local/src
tar xzvf xapian-bindings-0.9.4.tar.gz
cd xapian-bindings-0.9.4
ln -s /usr/local/xapian/bin/xapian-config /usr/local/bin/xapian-config #这里需要做个软连接,编译的时候需要用到
./configure –without-python #我没用到python,就不编译了
make
make install

进行到这一步,Xapian-bindings应该算是安装好了,但是不知道为何,编译好的xapian.so没有按说明文档所说的自动复制到php的extension目录,于是我手工完成这一步骤

cp php/.libs/xapian.so /usr/local/lib/php #/usr/local/lib/php是我在php.ini设置的extension目录

然后修改php.ini
extension_dir = “/usr/local/lib/php/” #没有就加上
extension=xapian.so

安装全部完成,重启apache看看phpinfo:

php + xapian extension
一切ok:)


http://my.bymg.net/2007/08/31/phpxapian-extension%E7%9A%84%E5%AE%89%E8%A3%85/

标签: , ,

在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..

[1] http://svn.osafoundation.org/pylucene/trunk/jcc/jcc/README
_______________________________________________
pylucene-dev mailing list
pylucene-...@osafoundation.org
http://lists.osafoundation.org/mailman/listinfo/pylucene-dev


http://groups.google.com.pe/group/python-cn/browse_thread/thread/0f085de0eab6f039

标签: , ,

Java下的框架编程(5)--cglib的应用

反射、Proxy和元数据是Java最强的三个特征,再加上CGLib (Code Generation Library)和ASM,使得Java虽然没有Ruby,Python般后生可畏,一样能做出强悍的框架。
Proxy 可以看作是微型的AOP,明白提供了在继承和委托之外的第三个代码封装途径,只要有足够的想象力,可以做得非常好玩,Spring的源码里用Proxy就 用得很随便,看得我非常眼红。可惜Proxy必须基于接口。因此Spring的做法,基于接口的用proxy,否则就用cglib。AOP么,一般小事非 compoent一级的就不麻烦AspectJ出手了。

cglib的Enhancer说起来神奇,用起来一页纸不到就讲完了。
它的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数:
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)

在 intercept()函数里,你可以在执行Object result=proxy.invokeSuper(o,args);来执行原有函数,在执行前后加入自己的东西,改变它的参数值,也可以瞒天过海,完全 干别的。说白了,就是AOP中的around advice。

AOP没有出现以前,该领域经典的设计模式是Decorator,像Java IO Stream的设计就是如此.不过,如果为每个DAO, 每个方法的写Decorator函数会写死人的,所以用上cglib的好处是一次过拦截所有方法。

另外,cglib除了Enhancer之外,还有BulkBean和Transform,都是Hibernate持久化的基础,但文档贫乏,一时还没去看怎么用。

1.AOP里讲了一百遍阿一百遍的log aspect在cglib是这样做的:


public class LogDAOProxy implements MethodInterceptor
{
private Logger log=Logger.getLogger(LogDAOProxy.class);
private Enhancer enhancer=new Enhancer();
//返回DAO的子类
public Object getDAO(Class clz)
{
enhancer.setSuperclass(clz);
enhancer.setCallback(
this);
return enhancer.create();
}
//默认的拦截方法
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable
{
log.info(
"调用日志方法"+method.getName());
Object result
=proxy.invokeSuper(o,args);
return result;
}
}

应用的代码:
LogDAOProxy proxy = new LogDAOProxy();
GoodsDAO dao
= (GoodsDAO)proxy.getDAO(GoodsDAO.class);
dao.insert(goods);

2.而在Spring的管理下应该略加修改的高级Decorator
上面的例子用return enhancer.create();创建子类实例,但在Spring管理下,一些Bean的实例必须由Spring来创建和管理,而不由enhancer来创建的。所以我对上述用法略加修改,使它真正当一个Proxy的角色,请对比黑体字的部分


public class LogDAOProxy implements MethodInterceptor
{
private Logger log=Logger.getLogger(LogDAOProxy.class);
private Object dao=null;
private Enhancer enhancer=new Enhancer();
//返回DAO的子类
public Object getDAO(Class clz,Object dao)
{
this.dao = dao;
enhancer.setSuperclass(clz);
enhancer.setCallback(
this);
return enhancer.create();
}
//默认的拦截方法
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable
{
log.info(
"调用日志方法"+method.getName());
Object result
=proxy.invoke(dao, args);
return result;
}
}

可见,原来模式里在getDao()时由enhancer创建dao,而 调用intercept时则将enhancer创建的dao以Object o参数传回。
而新模式里,dao在getDao()时从外面传入,enhancer.create()返回的是一个proxy. 而调用intercept时,实际会用之前传入的dao进行操作,而忽略Object o参数传入的proxy.

有点遗憾, intercept函数里MethodProxy的Signature是固定的 , 即客户如果调用foo(String),你不可以用proxy.invoke偷换成foo(String,String);

http://www.builder.com.cn/2008/0530/893236.shtml

标签:

《发布一个python的分词模块》的相关内容

中文分词的相关内容。

http://www.javaeye.com/wiki/topic/163334

标签:

自己写的一个基于词库的lucene分词程序--ThesaurusAnalyzer

前一段时间用lucene做一个搜索程序,找了好长时间的中文分词程序,都没找到合适的,最后自己弄了一个.现在共享出来.希望对大家有用.
分词算法: 基于词库的正向最大匹配算法.
分词词库用的是网上一个叫 segmenter 的分词程序使用的词库.
地址:www.mandarintools.com/segmenter.html
这个segmenter分词程序是把文件按行读取出来,然后把一行假设为一个词,从库中匹配,如果匹配不成功,则去掉一个字,再继续匹配.这样的分词程 序,其一,不便在lucene中使用,因为lucene的analyzer是通过Tokenizer分词的,而Tokenizer中一般是对字符流进行处 理,每次next返回一个Token,并不是一次性把内容读取进来,处理后再返回结果.其二,按行读取会有个缺点,就是如果文本中恰好把一个词用换行符隔 开了,这样这个词也就被切开了,没有被当作一个词处理.

我的程序实现方式:把词库读进内存后构建一个词语树.树的每个节点包含一个字. 比方 中国 中国人 中华民族 中华人民共和国 几个词,构成的树的结构:


国^ 华
人^ 人 民
民 族^


国^

懒得上传图片,所以将就着这样表示了.^表示该节点可以构成一个词.分词的过程类似于输入法的联想功能.读取一个字,然后联想,直到联想到不能为止.如果 当前可以构成词,便返回一个Token.如果当前不能构成词语,便回溯到最近的可以构成词语的节点,返回.最差的情况就是返回第一个单字.然后从返回结果 的下一个字重新开始联想.

lucene自带的几个分词程序中,ChineseAnalyzer是按字分的,与StandardAnalyzer对中文的分词没有大的区别.CJKAnalyzer是按两字切分的,比较武断,并且会产生垃圾Token,影响索引大小.

本分词程序的效果取决与词库.您可以用自己的词库替换程序自带的词库.词库是一个文本文件,名称为word.txt. 每一行一个词语,以#开头表示跳过改行.最后保存为UTF-8的文本.

程序的缺陷:
没有加入识别人名和地名的功能

该分词的一个应用案例:http://www.cyonline.net

这个网站是我给学校做的,用lucene对pdf ,word,excel,html等多种格式的文档进行解析,索引,提供全文搜索,并实现摘要高亮.这个网站在教育网上,公网用户可能访问起来比较慢.


附件1为分词程序的jar包

附件2为分词程序的源码,需要lucene-core.jar,一个比较Analyzer的测试类还需要lucene-analyzers.jar.

有问题或者意见建议请与我联系 jolestar@hotmail.com jolestar@gmail.com

http://www.javaeye.com/topic/58701

标签:

介绍:最新的一种中文分词方式——由字构词

现有的中文分词方法基本上都是采用基于词表的正向最大匹配法进行词语切分。不过这种分词方法具有一个最大的问题,对于未登录词(也就是在词表中并未录入的 词)的切分具有先天的不足,一般的解决方法是在基于正向最大匹配法切分模块后再加入一个未登录词模块,用于处理对于未登录词的切分。而在中文分词技术中, 对于未登录词的切分错误极大的影响到了整体分词的召回率。现在主流的分词算法对于未登录词的召回率仍然在0.6 左右。
最新的一种分词算法叫做“由字构词”的分词方法,关于“由字构词”分词方法的最早的一篇论文发表在2002 年第一届SIGHAN 研讨会上,紧接着Xue 在ME 模型上实现了由字构词的分词系统参加了Bakeoff2003 的评测,获得了封闭测试项目的第二名,让人瞩目的是,它对于未登录词的召回率高达0.7以上。而在Bakeoff2005 的各项赛事中,基于由字构词方法的分词系统几乎囊括了开放和封闭测试的全部冠军!而到了Bakeoff2006,由微软亚洲研究院采用基于CRF 模型实现的由字构词分词系统,获得了参加的六项评测中的四个第一,两个第三。
由字构词的分词方法和以往的分词方法不同,它是把分词视为一个字的分类问题。在微软亚洲研究院的系统中,他们把字分成了六类:S(单独成词)、 B(词首)、B2(词中第二个字)、B3(词中第三个字)、M(词中)、E(词尾)。比如以下的分词结果,可以将字标注为以下形式:
Java代码 复制代码
  1. /上海/计划/到/本/世纪/末/实现/人均/国内/生产/总值/五千美元/。/
  2. 上/B海/E计/B划/E到/S本/S世/B纪/E末/S实/B现/E人/B均/E国/B内/E生/B产/E总/B值/E五/B千/B2美/B3元/E。/S

那么最后可以形成一个字库,规定每个字的词位标记中某一个词位超过50%,那么就认为这个词位是这个字的主词位,否则就认为这个字是自由字。在现有的资料中,语料库中总字量为5147 个,有主词位的字为3920 个,占据总字量的76%。
个人感觉由字构词的分词方法有两个优点:
1、能很好的切分未登录词,而使中文分词切分召回率得到显著提高
2、词表非常小,中文中172个汉字就占据了所有中文用字的50%以上,常用汉字也就2000多个,比起基于最大匹配法所用到的词表小了非常多。

上面只是一个简单的介绍,希望有兴趣的同学可以一起研究研究:)
http://www.javaeye.com/topic/129769

标签:

Lucene中文分词 “庖丁解牛”

附件 为Qieqie设计编写的组件,中文分词“庖丁解牛”,具有相当好的使用价值。。。

高效率:QieQie的赛扬PC 1 秒解析 >>> 20000汉字的词语 (实际测试结果数据,可达1秒10万+汉字)
高可维护性:使用“庖丁”隐喻,形象明晰
高灵活性,可扩展:OOD

对比:《终于突破中文分词的效率问题》http://www.lucene.org.cn/read.php?tid=54&fpage=2 他的效率为 6秒 解析2588汉字

2007-08-08:

由于庖丁解牛进行了一些调整和重构,这里的附件代码已经是"较旧"的,最新的下载地址:

http://code.google.com/p/paoding/downloads/list

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

同时也可以通过浏览器访问http://paoding.googlecode.com/svn/trunk/paoding-analysis/ 直接浏览代码。

最新的在JavaEye的发布帖子是:

http://www.javaeye.com/topic/110148 中文分词 庖丁解牛 2.0.0 发布

http://www.javaeye.com/topic/49441

标签: ,

Lucene倒排索引原理

Lucene是一个高性能的java全文检索工具包,它使用的是倒排文件索引结构。该结构及相应的生成算法如下:

0)设有两篇文章1和2
文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too.
文章2的内容为:He once lived in Shanghai.

1)由于lucene是基于关键词索引和查询的,首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施
a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。
b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉
c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。
d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”
e.文章中的标点符号通常不表示某种概念,也可以过滤掉
在lucene中以上措施由Analyzer类完成

经过上面处理后
文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
文章2的所有关键词为:[he] [live] [shanghai]

2) 有了关键词后,我们就可以建立倒排索引了。上面的对应关系是:“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。文章1,2经过倒排后变成
关键词 文章号
guangzhou 1
he 2
i 1
live 1,2
shanghai 2
tom 1

通 常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:a)字符位置,即记录该词是文章中第几个字 符(优点是关键词亮显时定位快);b)关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记 录的就是这种位置。

加上“出现频率”和“出现位置”信息后,我们的索引结构变为:
关键词 文章号[出现频率] 出现位置
guangzhou 1[2] 3,6
he 2[1] 1
i 1[1] 4
live 1[2],2[1] 2,5,2
shanghai 2[1] 3
tom 1[1] 1

以live 这行为例我们说明一下该结构:live在文章1中出现了2次,文章2中出现了一次,它的出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现 频率来分析,文章1中出现了2次,那么“2,5”就表示live在文章1中出现的两个位置,文章2中出现了一次,剩下的“2”就表示live是文章2中第 2个关键字。

以上就是lucene索引结构中最核心的部分。我们注意到关键字是按字符顺序排列的(lucene没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词。

实 现时 lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信 息。

Lucene中使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。

为 了减小索引文件的大小,Lucene对索引还使用了压缩技术。首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例 如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。其次大量用到的是对数字的压缩,数字只保存与上一个值 的差值(这样可以减小数字的长度,进而减少保存该数字需要的字节数)。例如当前文章号是16389(不压缩要用3个字节保存),上一文章号是16382, 压缩后保存7(只用一个字节)。

下面我们可以通过对该索引的查询来解释一下为什么要建立索引。
假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。
而用普通的顺序匹配算法,不建索引,而是对所有文章的内容进行字符串匹配,这个过程将会相当缓慢,当文章数目很大时,时间往往是无法忍受的。

http://www.cnitblog.com/donne/archive/2007/12/04/37331.html

标签:

Python下的Lucene,PyLucene

下一个项目准备用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还没有支持中文全文检索的模块吧?

http://www.cnblogs.com/unfish/archive/2006/10/25/539956.html

标签: , ,