我有一个Node.JS服务器,并且其中有一个字典(哈希/映射)(键是一个数字,值-数组)。字典的每个元素都是ID(字符串)的数组,并且包含许多元素。数组的每个元素在数组中都是唯一的。例如:
let map = {2333:['id1', 'id2', 'id3', 'id4'], 1234:['id3', 'id4', 'id5'], 123213:['id4', 'id5', 'id77']}
服务器有一些查询,这些查询将新元素添加到数组或字典中。这种情况确实经常发生。还有另一种查询,以字典中的几个键为参数。我需要遍历该集合,通过集合中的键找到字典中的所有数组,并计算每个ID出现的次数。这是我简单的解决方案:
let queryArray = [1234, 123213];
let result = {};//Resulting hash of ID's occurrences
for(let i=0; i<queryArray.length; i++){
let key = queryArray[i];
if(!key) continue;
let array = map[key];
for(let j=0; j<array.length; j++){
let id = array[j];
if(!result[id]) result[id] = 0;
result[id]++;
}
}
//result = {'id3':1, 'id4':2, 'id5':2, 'id77':1};
此操作实际上经常在服务器上发生,我需要以某种方式对其进行优化。你有什么想法?答案的编程语言无关紧要。
答案 0 :(得分:1)
您可以仅为计数查询创建元数据对象。
如果您负担得起重复拥有的数据大小,则可以应用此方法。
let map = {
2333:['id1', 'id2', 'id3', 'id4'],
1234:['id3', 'id4', 'id5'],
123213:['id4', 'id5', 'id77']
}
let counts = {
2333: { id1: 1, id2: 1, id3: 1, id4: 1 },
1234: { id3: 1, id4: 1, id5: 1 },
123213: { id4:1, id5: 1, id77: 1 }
}
当然,每次添加对象时,您还需要更改计数对象。您可能还考虑创建一个作业,以确保计数和地图对象同步。如果没有,请更正。
并且根据您的内存要求,您可能希望在首次请求时创建计数对象。一段时间“不活动”后,您可以清除一些结果。
总而言之,您可以将此问题视为预缓存问题
答案 1 :(得分:0)
只需创建第二张地图作为反向字典:
let map = {
2333: ['id1', 'id2', 'id3', 'id4'],
1234: ['id3', 'id4', 'id5'],
123213: ['id4', 'id5', 'id77']
}
let idcounts = {
'id1': 1,
'id2': 1,
'id3': 2,
'id4': 3,
'id5': 2,
'id77': 1
}
在添加新的idcounts[id]
时增加id
,在删除时减小。
如果您有很多重叠的ID,请考虑创建一个单独的映射,将ID字符串映射到整数键,然后使用字典中的整数。
已经说过,Node.JS的单线程体系结构确实不适合CPU或内存密集型工作。您可能要考虑将查找工作转移到Redis等外部服务,或者使用Go或C ++等语言,并在地图周围使用互斥锁,以允许并行查找访问。