为什么whoosh提交这么慢
我在想,为什么使用下面的代码时,whoosh的速度有点慢。尤其是提交操作,花的时间特别长。
我试着把写入器的limitmb设置为2048,而不是默认的128,但几乎没有什么变化。根据建议,我把写入器的procs设置为3,这样索引的速度稍微快了一点,但提交的速度反而更慢了。而且commit(merge=False)在这里也没什么帮助,因为索引是空的。
我得到的结果是这样的:
index_documents 12.41 seconds
commit 22.79 seconds
run 35.34 seconds
对于这样一个小的结构和大约45000个对象来说,这个结果似乎有点多。
我是在whoosh 2.5.7和Python 2.7上测试的。
这是正常现象吗?还是我期待得太高了,或者我做错了什么?
我也做了一些性能分析,发现whoosh似乎在写出和读取很多的pickle文件。这似乎与事务处理的方式有关。
from contextlib import contextmanager
from whoosh import fields
from whoosh.analysis import NgramWordAnalyzer
from whoosh.index import create_in
import functools
import itertools
import tempfile
import shutil
import time
def timecall(f):
@functools.wraps(f)
def wrapper(*args, **kw):
start = time.time()
result = f(*args, **kw)
end = time.time()
print "%s %.2f seconds" % (f.__name__, end - start)
return result
return wrapper
def schema():
return fields.Schema(
path=fields.ID(stored=True, unique=True),
text=fields.TEXT(analyzer=NgramWordAnalyzer(2, 4), stored=False, phrase=False))
@contextmanager
def create_index():
directory = tempfile.mkdtemp()
try:
yield create_in(directory, schema())
finally:
shutil.rmtree(directory)
def iter_documents():
for root in ('egg', 'ham', 'spam'):
for i in range(1000, 16000):
yield {
u"path": u"/%s/%s" % (root, i),
u"text": u"%s %s" % (root, i)}
@timecall
def index_documents(writer):
start = time.time()
counter = itertools.count()
for doc in iter_documents():
count = counter.next()
current = time.time()
if (current - start) > 1:
print count
start = current
writer.add_document(**doc)
@timecall
def commit(writer):
writer.commit()
@timecall
def run():
with create_index() as ix:
writer = ix.writer()
index_documents(writer)
commit(writer)
if __name__ == '__main__':
run()
1 个回答
在这个提交过程中,有一些段落正在合并;这也解释了为什么设置 procs=3
会让事情变得更慢(因为要合并更多的段落!)。
对我来说,解决办法是设置 multisegment=True
,正如这里所建议的那样。
writer = ix.writer(procs=4, limitmb=256, multisegment=True)
你可以根据需要调整 procs
和 limitmb
,但要记住limitmb
是针对每个 procs 的!(也就是说,它们是相乘的)
注意:这会影响搜索速度。例如:
10000 个文档:
~200毫秒(不使用 multisegment)对比 1.1秒(使用 multisegment)
50000 个文档:
~60毫秒(不使用 multisegment)对比 ~100毫秒(使用 multisegment)
在我的系统上,commit
过程大约慢了 40%。我没有测量索引的时间,但 multisegment
也快得多。
这可能是原型设计的解决方案。一旦你确认了所需的 Schema
和参数,就可以把 multisegment
设置回 False
,然后再运行一次。
所以只是给你一个大概念……