JavaScript base64string->;二进制值->;[整数]。。。性能改进

JavaScript base64string->;二进制值->;[整数]。。。性能改进,javascript,binary,base64,Javascript,Binary,Base64,我正在使用Parse Server,并试图加速使用bloom过滤器的查询 每个文档都有一个字段bf,其数值范围为0…bloomSize,例如文档Id“xyz”散列为bf=6462 然后,查询加载二进制bloom筛选器值,这些值被编码并保存为base64字符串。为了在Parse Server/MongoDB中使用索引查询,我需要生成一个整数数组,然后与上面提到的字段进行比较。所以base64字符串需要解码,对于二进制数据中的每个0,我必须附加一个0值位置的整数。目前我正在使用以下代码段: //lo

我正在使用Parse Server,并试图加速使用bloom过滤器的查询

每个文档都有一个字段
bf
,其数值范围为0…bloomSize,例如文档Id“xyz”散列为
bf=6462

然后,查询加载二进制bloom筛选器值,这些值被编码并保存为base64字符串。为了在Parse Server/MongoDB中使用索引查询,我需要生成一个整数数组,然后与上面提到的字段进行比较。所以base64字符串需要解码,对于二进制数据中的每个0,我必须附加一个0值位置的整数。目前我正在使用以下代码段:

//loading [UInt8] from saved base64 string
const buf = new Buffer.from(request.user.get("daBlm"), 'base64');

var blm = Array()

for (var i = 0; i < buf.length; i++) {
    //iterating through 8-bit chunks and convert each UInt8 into string
    //as "toString" does not respect 8-bit length we chain ".padStart(8, '0')"
    const byte = buf[i].toString(2).padStart(8, '0');
    //loop through characters and for each 0, push the position into array
    for (var l = 0; l < byte.length; l++) {
        //push int to array for each bloom 0 value - not used bit
        if (byte[l] == "0") {
            blm.push(i*8 + l);
        } 
    }
}
//at the end is the blm array user in containedIn query constraint that use indexes    
dateQuery.containedIn("bf", blm);
有人知道如何加快速度吗

EDIT2+3

我将函数移动到单独的代码中,这些代码保持相同的行为,但允许我在其他函数中重用它。后来根据@Jonas的建议,我试图避免字符串转换:

Buffer.prototype.toIntegerArray = function() {
    const buffLenght = this.length;
    if (buffLenght > 0) {
        const arr = Array();
        arr.lenght = buffLenght * 8
        for (var i = 0; i < buffLenght; i++) {
            //iterating through 8-bit chunks
            for (var l = 0; l < 8; l++) {
                //push int to array for each bloom 0 value - not used bit
                //corrected syntax
                if (((this[i] >> l) & 1) === 0) {
                    arr.push(i*8 + l);
                }
            }
        }
        return arr;
    }
    return [];
}
Buffer.prototype.toIntegerArray=function(){
const buffLenght=此长度;
如果(bufflength>0){
常量arr=Array();
arr.lenght=buffLenght*8
对于(变量i=0;i>l)&1)==0){
方位推力(i*8+l);
}
}
}
返回arr;
}
返回[];
}
根据@Jonas注释,正确的语法确实可以找到零。通过控制台时间戳测量查询的数组构建部分,平均10个查询响应,65536位bloom大小为0(最终随机为半满bloom,所有查询响应相同):

  • toString(2).padStart(8,'0')
    =>~303ms(152ms)
  • 开关
    =>~322ms(145ms)
  • ((这个[i]>>l)和1)==0)
    =>~340ms
  • (变量掩码=0x80;掩码>0;掩码>>=1)
    =>~354ms
  • if((字节&0x80)==0)arr.push(计数器)=>314ms(158ms)

  • 正如我从测量中注意到的,在全0数组中循环和随机半满开花之间有很大的区别。因此,我猜更大的部分会推动它自己


    我理解这种测量方法有一定的误导性,但环境是给定的(解析服务器云函数),不幸的是,我没有足够的经验在那里构建更复杂的调查。在DBaaS上作为共享服务器就越困难。

    如果使用
    .toString(2)
    避免转换为字符串,它应该会有所改进。另外,可以通过使用单独的计数器变量避免重复的
    i*8+l

    for (var i = 0, counter = 0; i < buf.length; i++) {
        var byte = buf[i];
        for (var mask = 0x80; mask > 0; mask>>=1) {
            if ((byte & mask) === 0) {
                blm.push(counter);
            }
            counter++;
        }
    }
    

    另外,应该避免重复的
    i*8
    (与上面的解决方案相同)。

    如果((buf[i]>>l)&1==0)
    也应该检查lth位是否为0。另一种想法是,似乎每个字符中的一个字符总是被解码为6位二进制。这样就可以生成一个从字符到零索引数组的查找表。在base64上迭代,查找并将这些结果推送到数组中。@Jonas如果是你的第一条评论,我仍然无法摆脱这两个循环,对吗?如果我理解正确的话,它会保存到string和padStart的转换吗?关于第二个想法,我读到switch的性能比lookup table好,我试过这样做,但不幸的是,它的性能并没有好多少。我将把它添加到我的问题中。如果代码有效,您可以检查您的问题是否与主题有关。啊,我的第一条评论由于运算符的前置性而不起作用,请添加另一对大括号
    ((此[I]>>l)&1)==0)
    谢谢您的输入。也许我的度量在某种程度上受到了客户端/服务器上实际负载的影响,但您的解决方案的排名仍然略低于@Jonas。我在某个地方读到,将大循环分解成子循环实际上是有帮助的(“达夫的东西…?)也许这里是附加的计数器,我是编程新手,抱歉。这是微优化,然后取决于你运行的JavaScript引擎…它的优化器是如何工作的……我增加了另一个变化。如果需要更多的速度改进,考虑移动到编译的语言。C或C++或删除BA。se64一起编码(不确定其用途).正如我从测量结果中注意到的,循环通过完整的0s数组和随机的半满bloom有很大的不同。因此,我猜更大的部分是推送本身。不幸的是,目前环境是由Parse Server定义的,也许稍后我可以转到ElasticSearch,在那里我可以提供“已使用的布卢姆过滤器的“可用”部分,而不是“可用”的部分,后者的数组要大得多。事实上,零越多,需要生成的数组就越长,因此没有出路。
    Buffer.prototype.toIntegerArray = function() {
        const buffLenght = this.length;
        if (buffLenght > 0) {
            const arr = Array();
            arr.lenght = buffLenght * 8
            for (var i = 0; i < buffLenght; i++) {
                //iterating through 8-bit chunks
                for (var l = 0; l < 8; l++) {
                    //push int to array for each bloom 0 value - not used bit
                    //corrected syntax
                    if (((this[i] >> l) & 1) === 0) {
                        arr.push(i*8 + l);
                    }
                }
            }
            return arr;
        }
        return [];
    }
    
    for (var i = 0, counter = 0; i < buf.length; i++) {
        var byte = buf[i];
        for (var mask = 0x80; mask > 0; mask>>=1) {
            if ((byte & mask) === 0) {
                blm.push(counter);
            }
            counter++;
        }
    }
    
    for (var i = 0, counter = 0; i < buf.length; i++, counter+=8) {
        var byte = buf[i];
        if ((byte & 0x80) === 0) blm.push(counter);
        if ((byte & 0x40) === 0) blm.push(counter+1);
        if ((byte & 0x20) === 0) blm.push(counter+2);
        if ((byte & 0x10) === 0) blm.push(counter+3);
        if ((byte & 0x08) === 0) blm.push(counter+4);
        if ((byte & 0x04) === 0) blm.push(counter+5);
        if ((byte & 0x02) === 0) blm.push(counter+6);
        if ((byte & 0x01) === 0) blm.push(counter+7);
    }
    
    case "A": //000000
        arr.push(i*8, i*8+1, i*8+2, i*8+3, i*8+4, i*8+5);break;