【问题标题】:Creating a HashMap as an index for title keywords to improve search efficiency创建一个HashMap作为标题关键字的索引,提高搜索效率
【发布时间】:2013-11-12 00:04:05
【问题描述】:

我有一个自定义类Disks,它存储CD 的各种信息,例如标题、长度、艺术家等。这些Disks 对象存储在ArrayList 中,它只能添加Disks 的元素。我正在使用一种方法来根据匹配它们的标题来搜索这些对象。它接受用户输入,然后遍历列表的每个元素,并比较用户关键字和 CD 的标题。如果完全匹配,则将其信息返回给用户。

我想通过合并一个 HashMap 来稍微改变这个搜索机制。我希望对每个 Disks Title 进行标记,然后为关键字创建一个映射条目。

下面是一个示例:“汽车”一词出现在位置 0、5、7 的ArrayList 元素的标题中。我希望能够为“汽车”创建一个映射条目,该条目将是一个列表 [0,5,7]。如果将另一个元素添加到位置 10 的 ArrayList,标题中带有“Cars”,我将如何修改旧的映射条目以使新列表为 [0,5,7,10]?

最后我希望用户搜索标题关键字“Loud Cars”。我会先在索引中找到“loud”得到[0,7,5]的列表(例如),然后找到“cars”得到[0,5,7,10]的列表。然后,我将找到这些列表相交的位置并返回与这些位置对应的ArrayList 元素。

我当前的 HashMap 声明如下所示:public HashMap<String, ArrayList<Integer>> map = new HashMap<>(); 然而,即使 Key 不同,存储在 ArrayList 中的值也是相同的,因为它们只有一个。

我的Disks ArrayList 是:public ArrayList<Disks> items; 有没有办法将此 ArrayList 合并到 HashMap 的 Value 中?

【问题讨论】:

  • however even when the Key is different, the values stored in the ArrayList are the same because there is only one of them. 你能说得更具体点吗?为什么只有索引 ArrayList 的一个实例?另外,你能告诉我们你是如何将这对夫妇添加到地图上的吗?
  • 因为随着可能键的数量增加,我不需要新的索引 ArrayList 吗?

标签: java search arraylist hashmap


【解决方案1】:

为“汽车”的索引条目添加一个新值

map.get("Cars").add(10);

这样做的安全方法(key = "Cars", index = 10):

ArrayList<Integer> entry = map.get(key);
if (entry == null) {
  entry = new ArrayList<Integer>();
  map.put(key, entry);
}
entry.add(index);

而不是使用

HashMap<String, ArrayList<Integer>>

我会推荐

HashMap<String, HashSet<Integer>>

自动避免重复。

当你搜索多个单词时,使用retainAll构建多个集合的交集(但复制第一个集合,因为retainAll是破坏性的):

Set<Integer> resultSet = new HashSet<Integer>();
resultSet.addAll(map.get("Cars"));
resultSet.retainAll(map.get("Loud"));

【讨论】:

  • 那么这将获取 Key Cars,然后将 10 添加到关联的数组列表中?
  • 是的,它获取键“Cars”的映射值,这是一个arraylist,并将10附加到arraylist。
  • 所以如果我有键“声音”并与位置 9 执行相同的操作,它会自动将 9 附加到与“声音”关联的列表中,而只留下“汽车”的列表?
  • 是的,如果您参考上面的“安全方式”。
【解决方案2】:

您需要为每个字符串映射到一个值创建一个新的 Integer ArrayList。第一次使用条目时,您创建一个新列表(您必须检查该字符串是否映射为 null),并将新磁盘条目将存储在 Disls 的 ArrayList 中的索引值添加到您的 ArrayList整数。每当字符串映射到非空列表时,您只需将索引(它在磁盘 ArrayList 中的位置)添加到 Integer 的 ArrayList。

【讨论】:

  • 我喜欢这个答案,但我怎样才能动态创建这些整数数组列表?
  • 每次将磁盘添加到列表时,都会标记标题。对于每个标记,您会查看 Hashmap 中是否已经存在 Arraylist,如果没有(它为 null),您会说 map.put(disk.title(),new ArrayList());
  • 我想我现在找到了我的断开连接。我没有意识到 HashMap 可以跟踪新的 arrayLists,因为我需要为 Keys 创建它们。谢谢。
【解决方案3】:

老实说,我认为扩展解决方案的最佳方式是使用布隆过滤器或类似的复杂工具。这将需要您创建复杂的哈希码、管理误报等等。

话虽如此,根据您的设计,我认为您可以简单地将哈希映射指向也存储在数组列表中的 Disks 对象。

public HashMap<String, ArrayList<Disks>> map

对于关键字“汽车”,您有一个磁盘对象列表。对于关键字“loud”,您有另一个磁盘对象列表。只需使用retainAll() 方法获取两个列表并找到交集。

确保覆盖磁盘中的 hashCode() 和 equals(),以便所有集合都能正常工作。

【讨论】:

  • 这是有道理的,但是我要管理的磁盘类的数组列表太多了。
  • 是的,这就是缺点。这就是为什么我建议使用布隆过滤器。基本上,您需要计算每个 Disks 对象的哈希值。这样的哈希表示某些单词的存在或不存在(假设您的关键字数量有限且数量较少,这样更容易理解这种解决方案)。说这些词只是“大声”、“汽车”和“蓝色”。然后每个 Disks 对象将有一个哈希码,其值的范围可以从 000 到 111。如果您的关键字数量较大,那么显然您不能继续在哈希码中添加位。然后你需要处理误报。
  • 感谢您的意见,但我想我会接受 Stefan 提出的建议,这对于我的规模来说似乎简单且易于管理。
  • 要了解误报,请考虑另一个示例。第一位(最低有效位)表示标题中某处有字母“a”。那么“汽车”的第一位将有一个 1,但“猫”也是如此。这两个词非常相似,因此哈希码可能会欺骗您找到误报。我相信您的解决方案应该尝试组织这种复杂性。如果这是一个专业项目,我建议使用已经实现了这个的框架,例如 Apache Lucene。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多