[lucene] lucene搜索结果排序的问题
ybzshizds
2009-05-31
问题:
实体类: public class TraCourse{ private Integer courseId; ............. private Date updateDate; //更新时间 ...get set方法省略 } lucene搜索时,按updateDate进行排序,希望最新的TraCourse排在最前面 可是导致的后果是,用户频繁的对自己的TraCourse进行修改(其实内容没有进行修改,就是点击一下“修改”按钮,以修改updateDate为比较新的日期,让自己的TraCourse排在靠前的位置),这样一来数据库压力增大。不知大家有没有什么好的办法,谢谢! |
|
ybzshizds
2009-06-01
请各位仁兄帮忙想个好的解决办法!
|
|
luckaway
2009-06-02
如果实时性要求不高,可以先把更新数据存放到数据库里!隔一点的时间去更新一次
|
|
ybzshizds
2009-06-02
引用 如果实时性要求不高,可以先把更新数据存放到数据库里!隔一点的时间去更新一次 谢谢luckaway的回答! 实时性还是有点要求,我们现在是半个小时一次增量索引,这样和数据库之间的数据延迟就是半个小时了,但是用户只知道刷新自己的TraCourse,就可以将updateDate刷到比较新的日期,这样搜索出来的结果就会比较靠前。用户的心理是可以理解的,因为谁都想让自己发布的内容能在搜索时靠前显示。可是用户没事就刷新自己的TraCourse就没办法去控制了。 隔一点的时间去更新一次,我们现在是已经这样做了,可是还是没有好的办法去控制用户的刷新。难道是lucence搜索时,sort排序时按updateDate去排序是有问题的吗?或者是去设法控制用户刷新的次数(需求中又不允许这样做)? |
|
ybzshizds
2009-06-03
现在想到这样一种方式,在数据库中增加一张表,记录每个TraCourse在页面中被点击查看的次数,从0递增到20,达到20后,有归为0,这样就可以根据点击次数进行排序了,关键是点击次数也要做到索引中,而且点击次数是要频繁修改的,索引也要频繁修改。可是我们的索引大小已经达到6个G(500万条数据)了,对索引频繁修改肯定不合理。在网上查资料时,发现了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); 之后的操作和一般的搜索相同。 可是如何保证两个索引文件中Document的顺序是对应的,第一次新建的时候没问题(可以保证索引中Document的数量和顺序一致),可是当对点击次数对应的索引进行修改时,问题就暴露出来了,我们知道修改索引的做法是先删除后插入的,这样一来segement中的文档顺序就变了,如何保证两个索引文件的文档顺序一致呢,头痛中。。。。。。。。 |
|
chester60
2009-06-04
使用lucene是为了全文搜索,也就是说排序结果依赖于文本相关度。如果你需要按照时间来排,那就不是lucene这个系统的初衷。硬要把这个功能糅进去,那肯定是很麻烦的,走的路线就错了。你不妨换个角度,对lucene搜索的一部分结果集(比如100条数据)按照时间排序,这样解决问题的复杂度是相对小的。
当然你硬要用lucene解决一切也不是不可能,对于时间这种不需要分词的field,可以作为一个定长值保存在索引文件中。这样就可以直接修改索引文件内容,而不引起索引文件的长度变化(长度变化会引起偏移量变化,导致数据读取出错)。这样就解决了修改的问题,但是排序的问题还需要修改具体的评分细则,总体上来说复杂度很高,而且修改过后就没法同步更新lucene的版本了。 |
|
ybzshizds
2009-06-04
我们现在的做法就是按照时间进行排序的,所有的时间都被格式化成yyyyMMddHHmm形式的字符串保存到索引中了,然后按照更新时间进行降序排序的。目前搜索的速度还可以,0.0X的响应速度(不过搜索服务是用EJB去做的,专门用一台服务器在处理)
现在的问题是,排序规则要改为,用点击次数去排序,将点击次数做到索引中去,索引就要频繁修改了,因为每个TraCourse的点击次数一直在变,而索引是不方便一直去更改的。所以为了避免整个索引频繁修改,我们查看了lucene的api,找到了 ParallelReader api中对它的说明是这样的 有时对于一个Document(包含Field比较多)来说,有那么一两个Field会被频繁地修改,而另一些Field则不会。这时可以将频繁修改的Field和其他Field分开存放,而在搜索时同时检索这两部分Field而提取出一个完整的Document。 这要求两个索引包含的Document的数量必须相同, 在创建索引的时候,可以同时创建多个IndexWriter,将一个Document根据需要拆分成多个包含部分Field的Document,并将这些Document分别添加到不同的索引。 而在搜索时,则必须借助ParallelReader类来整合。 这样ParallelReader就正好满足我们的需求了嘛,但是现在问题的关键就是 如何保证两个索引文件的文档顺序完全一致呢 |