如何使用Lucene生成唯一标识符?

6
我正在使用Lucene来存储(以及索引)各种文档。
每个文档需要一个持久的唯一标识符(作为URL的一部分)。
如果我使用SQL数据库,我可以使用“整数主键auto_increment”(或类似)字段自动生成每个添加记录的唯一ID。
有没有办法用Lucene做到这一点?
我知道Lucene中的文档是编号的,但注意到这些数字随时间重新分配。
(我正在使用Lucene 3.0.3的Java版本。)

你不能只是索引一个UUID.randomUUID()并将其用作永久键吗? - sisve
理想情况下,我希望我的ID更短。 - dave4420
4个回答

4
如larsmans所说,您需要将此存储在单独的字段中。我建议您将该字段索引并存储,并使用KeywordAnalyzer进行索引。您可以在内存中保留一个计数器,并针对每个新文档进行更新。
剩下的问题是持久性 - 如何在Lucene进程停止时存储最大id。一种可能性是使用保存最大id的文本文件。
我相信Flexible Indexing将允许您将最大id作为“全局”字段添加到索引中。如果您愿意使用Lucene的主干版本,则可以尝试灵活的索引来查看它是否符合要求。

2
对于类似情况,我使用以下算法(与Lucene无关,但您仍然可以使用它)。
  • 创建新的AtomicLong。从System.currentTimeMillis()System.nanoTime()获取初始值。
  • 每个下一个ID都是通过调用该AtomicLong上的.incrementAndGet.getAndIncrement生成的。
  • 如果系统重新启动,则在启动期间将AtomicLong再次初始化为当前时间戳。
优点:简单、有效、线程安全、非阻塞。如果需要集群ID支持,只需在现有长整型上添加hi/lo算法的空间或牺牲一些高字节即可。 缺点:如果添加新实体的频率超过1/ms(对于System.currentTimeMillis())或1/ns(对于System.nanoTime()),则无法工作。不容忍时钟异常。
可以考虑使用UUID作为另一种选择。UUID中重复的概率几乎不存在

0

编辑:几位评论者提出了此方法可能存在的问题,由于时间有限,我无法进行全面测试。 我将其留在这里因为Yuval F.提到了它。 请不要无理地投反对票。

给定一个IndexWriter w,您可以使用 w.maxDoc() + 1 作为 id 并将其(作为字符串)存储在单独的Field中。 确保 Fieldstored


1
为什么要存储未建立索引的id字段?这难道不意味着我无法通过id进行搜索吗? - dave4420
1
此外,这不会受到合并的影响吗?当删除文档被修剪时,是否会重复使用ID? - sisve
对不起 @Dave,我误读了你的问题。如果您想要,当然可以对其进行索引。@Simon Svensson:API文档中指出“返回此索引中文档的总数(...不包括删除)”。 - Fred Foo
我认为这样做不行。假设有n个文档。添加第n+1个文档,再删除一个文档,再添加另一个文档。现在你有两个ID为n+1的文档。(如果合并索引等操作,你也会遇到麻烦。) - Xodarap
@Xodarap:如果我正确阅读了API文档(“不计算删除”),那么这种方法确实可以防止这种情况发生。事实上,这似乎就是为什么IndexWriter具有maxDocnumDocs方法的原因。 - Fred Foo
正如 Pascal 所提到的,一旦你进行了优化,seg 信息将不再包含已删除文档的计数。你可以使用 luke 进行尝试:删除、优化,然后查看计数是否包括你的删除。 - Xodarap

0

尝试在要索引的数据源中找到唯一值,并将其存储在lucene文档中。数据源可以是mysql数据库、文件系统等。

例如,如果您正在从mysql数据库索引内容,则可以使用表名和主键id“tablename_rowID”组装唯一的id。

假设您正在从两个表“pages”和“comments”表进行索引;对于页面表中的每一行,您可以使用“page_28”为您的页面表中id为28的行生成唯一id。同样地,假设您正在索引评论表中的第36行,则您的唯一id将为“comment_36”。

如果所有选项都失败了,那么我会坚持使用UUID。通过一些额外的谨慎措施,这可以是现在时间戳附加的UUID。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接