Java 在受约束的多对多数据集中高效地查找重复项?

Java 在受约束的多对多数据集中高效地查找重复项?,java,data-structures,duplicate-removal,Java,Data Structures,Duplicate Removal,我必须为我们的webapp写一个批量操作版本 允许您在更有限的基础上从UI执行操作。理想的 操作是将对象指定给类别。一个类别可以有 多个对象,但一个给定对象只能属于一个类别 该任务的工作流是: 1) 使用浏览器上载以下格式的文件: # ObjectID, CategoryID Oid1, Cid1 Oid2, Cid1 Oid3, Cid2 Oid4, Cid2 [etc.] 该文件很可能有几十到几百行,但是 肯定有几千行 在理想情况下,给定的对象id在文件中只出现一次 (反映一个对象只能指定

我必须为我们的webapp写一个批量操作版本 允许您在更有限的基础上从UI执行操作。理想的 操作是将对象指定给类别。一个类别可以有 多个对象,但一个给定对象只能属于一个类别

该任务的工作流是:

1) 使用浏览器上载以下格式的文件:

# ObjectID, CategoryID
Oid1, Cid1
Oid2, Cid1
Oid3, Cid2
Oid4, Cid2
[etc.]
该文件很可能有几十到几百行,但是 肯定有几千行

在理想情况下,给定的对象id在文件中只出现一次 (反映一个对象只能指定给一个类别的事实) 但由于该文件是在我们的控制之外创建的,因此无法保证 这实际上是真的,处理过程必须处理这种可能性

2) 服务器将接收文件,对其进行解析和预处理 并显示类似以下内容的页面:

723 objects to be assigned to 126 categories
142 objects not found
 42 categories not found

Do you want to continue?

[Yes]     [No]
3) 如果用户单击
Yes
按钮,服务器将 实际做这项工作

因为我不想在第(2)步和第(3)步中解析文件,所以 第(2)部分,我需要构建一个容器,它将跨越 请求并保存有用的数据表示形式,以便 轻松提供数据以填充“预览”页面,并让我 高效地完成实际工作。(虽然我们显然有会议,但我们 通常情况下,在内存中只保留很少的会话状态。)

有一个现有的

assignObjectsToCategory(Set<ObjectId> objectIds, CategoryId categoryId)
然后,当每个
(ObjectId,CategoryId)
对被读入时,它将 两张地图都有。一旦文件被完全读入,我 可以做:

for (Map.Entry<ObjectId, List<CategoryId>> entry : categoriesByObject.entrySet()) {
    List<CategoryId> categories = entry.getValue();
    if (categories.size() > 1) {
        ObjectId object = entry.getKey();
        if (!all_categories_are_equal(categories)) {
            illegalDuplicates.add(object);
            // Since this is an "illegal" duplicate I need to remove it
            // from every category that it appeared with in the file.
            for (CategoryId category : categories) {
                objectsByCategory.get(category).remove(object);
            }
        }
    }
}
for(Map.Entry:categoriesByObject.entrySet()){
列表类别=entry.getValue();
如果(categories.size()>1){
ObjectId object=entry.getKey();
如果(!所有类别都相等(类别)){
非法复制。添加(对象);
//由于这是一个“非法”的重复,我需要删除它
//从它出现在文件中的每个类别。
对于(类别ID类别:类别){
objectsByCategory.get(category).remove(object);
}
}
}
}
此循环完成后,
objectsByCategory
将不再包含任何“非法” 副本和
非法副本
将包含要复制的所有“非法”副本 根据需要进行汇报。然后,我可以迭代
objectsByCategory
,获取每个类别的
集合
,并调用
assignObjectsToCategory()
来执行赋值

但是,虽然我认为这会起作用,但我担心会将数据存储两次,尤其是 当输入文件很大时。我还担心我遗漏了一些东西:效率 这将非常缓慢

有没有办法做到这一点,不会使用双内存,但仍然可以快速运行? 我是否错过了一些即使使用两倍内存仍会大量运行的东西
比我预期的要慢?

考虑到您给出的限制,我不知道有什么方法可以使用更少的内存来实现这一点

不过,一种可能的优化方法是只维护在多个类别中列出的对象的类别列表,否则只需将对象映射到类别,即:

Map<CategoryId, Set<ObjectId>> objectsByCategory;  // HashMap
Map<ObjectId, CategoryId> categoryByObject; // HashMap
Map<ObjectId, Set<CategoryId>> illegalDuplicates;  // HashMap
MapObjectsByCategory;//哈希图
Map categoryByObject;//哈希图
映射非法副本;//哈希图
是的,这又增加了一个容器,但它(希望)只包含几个条目;此外,categoryByObject映射的内存需求也减少了(减少了每个条目的一个列表开销)

当然,逻辑要复杂一点。最初发现重复项时,应将该对象从categoryByObject映射中删除,并添加到非法重复项映射中。在将任何对象添加到categoryByObject映射之前,您需要首先检查illegalDuplicates映射


最后,在构建其他两个映射之后,在单独的循环中构建objectsByCategory映射可能不会影响性能,而且它会稍微简化代码。

如果用户在存在非法分配时选择继续,则应使用of,您希望发生什么?您是否实际分析了实现的内存和时间性能,或者这是一个理论上的担忧?1)这是理论上的,因为我还没有开始编写代码。2) 如果存在非法分配,则需要忽略它们(不执行)。
Map<CategoryId, Set<ObjectId>> objectsByCategory;  // HashMap
Map<ObjectId, CategoryId> categoryByObject; // HashMap
Map<ObjectId, Set<CategoryId>> illegalDuplicates;  // HashMap