lucene中ParallelReader.java使用中的难点

09-06-03 ybzshizds
需求:

表a 一对一 表b

表a 做到索引中后不需要频繁的修改

表b 做到索引中后会频繁的修改

索引查询时需要结合表a和表b中的字段进行连接查询

org.apache.lucene.index.ParallelReader的作用

有时对于一个Document(包含Field比较多)来说,有那么一两个Field会被频繁地修改,而另一些Field则不会。这时可以将频繁修改的Field和其他Field分开存放,而在搜索时同时检索这两部分Field而提取出一个完整的Document。

这要求两个索引包含的Document的数量必须相同, 在创建索引的时候,可以同时创建多个IndexWriter,将一个Document根据需要拆分成多个包含部分Field的Document,并将这些Document分别添加到不同的索引。

而在搜索时,则必须借助ParallelReader类来整合。

Directory dir1=FSDirectory.getDirectory(new File(INDEX_DIR1),false);

Directory dir2=FSDirectory.getDirectory(new File(INDEX_DIR2),false);

ParallelReader preader=new ParallelReader();

preader.add(IndexReader.open(dir1));

preader.add(IndexReader.open(dir2));

IndexSearcher searcher=new IndexSearcher(preader);

Directory dir1=FSDirectory.getDirectory(new File(INDEX_DIR1),false);Directory dir2=FSDirectory.getDirectory(new File(INDEX_DIR2),false)arallelReader preader=new ParallelReader();preader.add(IndexReader.open(dir1));preader.add(IndexReader.open(dir2));IndexSearcher searcher=new IndexSearcher(preader);

之后的操作和一般的搜索相同。

正好可以满足以上需求

可是如何保证两个索引文件中 Document的顺序是对应的,第一次新建的时候没问题(可以保证索引中Document的数量和顺序一致),可是当对表b对应的索引进行修改时,问题就暴露出来了,我们知道修改索引的做法是先删除后插入的,这样一来segement中的文档顺序就变了,如何保证两个表对应的索引文件的文档顺序一致,是个大难题,请有经验的高手慷慨解难,谢谢!

    

ybzshizds
2009-06-04 08:11
我们现在遇到的是这样的问题

每个用户在网站上都发布了自己的求购信息,为了实现对求购信息作全文检索,所以我们就用了lucene(半个小时做一次增量索引),检索出来的内容,我们按照求购信息的更新时间去排序,让最新发布的信息排名在最前面,本无可厚非,可是用户知道这个排序规则后就开始频繁的刷新自己的求购信息(求购信息的内容不修改,就只是点击修改按钮,这样该求购信息的更新时间就被刷为最新了,就可以在搜索结果中排在比较靠前的位置了,气愤的是用户没事就刷新自己的求购信息,数据库不堪负重)但是需求中又不允许限制用户刷新的次数,所以我们最后想出了一个折衷的方法,就是在数据库中新增一张表,记录每个求购信息被点击查看的次数,从0累加到50,达到50后,又归为0,以便让lucene对搜索结果的排序不再按照求购信息的更新时间来排序,而是按照点击次数来排序,所以点击次数就要加入到索引中了,这样一来索引文件就要频繁的修改了,因为点击次数一直在变化。最后就想到了用ParallelReader,将原来的一个索引文件拆分成两个(频繁修改的和不需要怎么修改的)可是ParallelReader要求两个索引文件包含的Document的数量和顺序完全一致,这个顺序问题就没办法了。不知道大家有没有更好的解决办法?

banq
2009-06-04 08:41
>但是需求中又不允许限制用户刷新的次数,所以我们最后想出了一个折衷的方法,

得从这里重新考虑,建议你使用缓存,无论怎么刷新,都是缓存中数据,然后你异步定时计算,根据一个IP多长时间访问一次算一次有效点击。

ybzshizds
2009-06-04 11:24
谢谢banq大哥的回答

  缓存现在还是没法去实现,因为客户每天同时在线的数量很大(近15万),而且求购信息的数量也很大(有400多万条,做成lucene索引也有3G),求购信息的内容也有近400汉字

而且lucene的索引是半个小时做一次(先去数据库中查更新的和新增的求购信息,然后添加到lucene素引中),另外网站使用了一种最简单的集群方式,不能使用缓存,连session

都不能使用(用的数据库保存session)

  因此我还是没有找到解决问题的办法!

  我们现在要解决的是客户发布求购信息后,借助lucene在搜索中搜索结果排名的问题,现在是根据求购信息的发布时间进行搜索结果的排名,客户都不满意,因为他们要去频

繁的刷新自己发布的求购信息以达到修改更新时间而竞争排名的目的。

  现在想根据点击次数循环计数(从0到50,达到50后又归为0)在搜索结果中进行排名,这样客户就不用频繁去刷新自己求购信息的更新时间了,而且所有客户发布的求购信息在

搜索结果中的暴光率也是平等的。

  lucene索引是不能频繁修改的,我们现在是半小时作一次增量索引可是加入点击次数到索引中后,索引就得频繁修改了,所以想到用lucene中的ParallelReader。但是

ParallelReader要求两个索引文件中包含的Document的数量和顺序完全一致,可是对于频繁修改的那个索引来说Document的顺序一直在变化。

[该贴被ybzshizds于2009-06-05 08:21修改过]

ybzshizds
2009-06-08 09:58
引用国外论坛上的一段回复,还是不懂如何去实现。郁闷!

> The alternative is to use one index. However, an update would require me to

> delete the entire document (which is quite large in my application) and

> reinsert it after making updates. This requires a lot more I/O and is a lot

> slower, and I'd like to avoid this if possible.

>

> I can think of other alternatives, but all involve storing data and/or

> bitsets in memory, which is not very scalable. I need to be able to handle

> millions of documents.

I'm in a very similar situation and we've taken the latter route. We

get a bitset for our primary (immutable) index and our secondary

(mutable) one and merge the results based on a unique ID in the matching

document in each index. This isn't super fast because we have to

instantiate a Document to get at this ID, but because the mutable index

contains a lot less information than the immutable one, it isn't too

bad. We then use the TermDocs to jump to the ID in the primary index

and set its bit.

It probably doesn't scale to millions of matches, but it scales pretty

well to tens of thousands. I'd suggest breaking down into smaller

indexes if you can, and run this process across each of them. That way

it'll take less memory and you can return the matches in batches

per-index.

[该贴被ybzshizds于2009-06-08 10:00修改过]

猜你喜欢
2Go 1 2 下一页