无锡cms建站,版式设计网站,aso优化分析,万网icp网站备案专题大多数使用Apache Lucene的搜索应用程序都会为每个索引文档分配唯一的ID#xff08;即主键#xff09;。 尽管Lucene本身不需要这样做#xff08;它可能不太在乎#xff01;#xff09;#xff0c;但应用程序通常需要它以后通过其外部ID替换#xff0c;删除或检索该文档… 大多数使用Apache Lucene的搜索应用程序都会为每个索引文档分配唯一的ID即主键。 尽管Lucene本身不需要这样做它可能不太在乎但应用程序通常需要它以后通过其外部ID替换删除或检索该文档。 大多数在Lucene之上构建的服务器例如Elasticsearch和Solr 都需要一个唯一的ID如果不提供则可以自动生成一个ID。 有时您的ID值已经预先定义例如如果外部数据库或内容管理系统分配了ID 或者您必须使用URI 但是如果您可以自由分配自己的ID那么哪种方法最适合Lucene 一个明显的选择是Java的UUID类该类生成版本4的通用唯一标识符 但事实证明这是性能上最糟糕的选择它比最快的速度慢4倍。 要了解原因需要对Lucene如何找到术语有所了解。 BlockTree术语词典 术语词典的目的是存储在索引期间看到的所有唯一术语并将每个术语映射到其元数据 docFreq totalTermFreq等 以及totalTermFreq 文档偏移量投递和有效载荷。 当请求一个术语时术语词典必须在磁盘索引中找到它并返回其元数据。 默认编解码器使用BlockTree术语词典 该词典以排序的二进制顺序存储每个字段的所有术语并将这些术语分配到共享公共前缀的块中。 默认情况下每个块包含25到48个词。 它使用内存中的前缀三叉戟索引结构 FST 将每个前缀快速映射到相应的磁盘块并在查找时首先根据请求的术语的前缀检查索引然后在-disk块并扫描以查找术语。 在某些情况下当段中的术语具有可预测的模式时术语索引可以知道请求的术语不能存在于磁盘上。 这种快速匹配测试可以带来可观的性能提升尤其是当索引很冷操作系统的IO缓存不缓存页面时因为它避免了昂贵的磁盘搜寻。 由于Lucene是基于段的因此单个id查找必须访问每个段直到找到匹配项因此快速排除一个或多个段可能是一个大胜利。 保持细分受众群的数量尽可能少也很重要 鉴于此完全随机的id例如UUID V4 应该会表现最差因为它们击败了术语索引快速匹配测试并且需要对每个段进行磁盘搜索。 具有可预测的每段模式的ID例如顺序分配的值或时间戳应发挥最佳作用因为它们将使术语索引快速匹配测试的收益最大化。 测试性能 我创建了一个简单的性能测试器来验证这一点。 完整的源代码在这里 。 该测试首先将1亿个ID索引到具有7/7/8段结构7个大段7个中段8个小段的索引中然后搜索200万个ID的随机子集记录最佳时间5次。 我在Ubuntu 14.04上使用Java 1.7.0_55以及3.5 GHz Ivy Bridge Core i7 3770K。 由于Lucene的术语从4.0开始是完全二进制的 因此存储任何值的最紧凑的方法是二进制形式其中每个字节使用所有256个值。 然后一个128位ID值需要16个字节。 我测试了以下标识符来源 顺序ID0、1、2...采用二进制编码。 零填充的顺序ID00000000、00000001等采用二进制编码。 纳米时间二进制编码。 但是请记住 纳米时间是棘手的 。 使用此实现从时间戳nodeID和序列计数器派生的UUID V1 。 UUID V4 使用Java的UUID.randomUUID()随机生成。 片状ID 使用此实现 。 对于UUID和Flake ID除了标准16或36基编码之外我还测试了二进制编码。 请注意我仅使用一个线程测试了查找速度但是在添加线程时结果应该线性扩展在足够并行的硬件上。 用二进制编码的零填充顺序ID最快比非零填充顺序ID快很多。 UUID V4使用Java的UUID.randomUUID() 慢了约4倍。 但是对于大多数应用程序来说顺序编号是不实际的。 第二快的是UUID V1 以二进制编码。 令我惊讶的是这比Flake ID快得多因为Flake ID使用相同的原始信息源时间节点ID序列但是以不同的方式对位进行混洗以保留总体顺序。 我怀疑问题在于在获取不同文档之间的数字之前必须在片状ID中遍历的通用前导数字的数目因为64位时间戳的高位在先而UUID V1则在低位位首先是64位时间戳。 当一个字段中的所有术语共享一个公共前缀时术语索引也许可以优化这种情况。 我还分别测试了10、16、36、64、256的基数通常对于非随机ID较高的基数更快。 我对此感到惊讶因为我希望与BlockTree块大小25到48匹配的基数最好。 此测试有一些重要警告欢迎补丁 一个真正的应用程序显然比简单地查找id还要做更多的工作并且结果可能会有所不同因为热点必须编译更多活动的代码。 在我的测试中该索引非常热有大量RAM可以容纳整个索引 对于冷索引我希望结果会更加鲜明因为避免磁盘搜索变得非常重要。 在实际应用中使用时间戳的id在时间上会更加分散 我可以通过伪造更大范围的时间戳来“模拟”自己。 也许这会缩小UUID V1和Flake ID之间的差距 我在索引编制过程中只使用了一个线程但是具有多个索引编制线程的实际应用程序会将ID一次分散到多个段中。 我使用了Lucene的默认TieredMergePolicy 但是有一种更聪明的合并策略可能会支持那些ID更加“相似”的合并段从而可能会产生更好的结果。 该测试不执行任何删除/更新操作这将在查找期间需要进行更多工作因为如果给定的ID已被更新除其中一个以外的所有其他ID则该ID可能位于多个段中。 最后我使用了Lucene的默认编解码器但是当您愿意将RAM换成更快的查询时我们有不错的发布格式针对主键查找进行了优化例如去年的Google夏季代码项目和MemoryPostingsFormat 。 这些可能会提供可观的性能提升 翻译自: https://www.javacodegeeks.com/2014/05/choosing-a-fast-unique-identifier-uuid-for-lucene.html