使用标签数组提高标签算法的性能

时间:2018-12-10 12:16:32

标签: javascript node.js performance

这是我的课程Sample

Sample实例可以:

  • 具有许多标签,例如Tag1Tag2
  • 使用方法isTagged来查询它是否已被标记(即!Tag1

    function Sample(){
        // [..]
        this.tags = [];
        // [..]
    }

    Sample.prototype.tag = function(tags){
        // [..]
        this.tags[tags] = true;
        // [..]
    };

    // if an array is passed, isTagged will return true at the first match ie. not all need to match, just one
    Sample.prototype.isTagged = function(tag){

        if(tag){
            if(Array.isArray(tag)){

                let tLength = tag.length;

                while(tLength--){
                    if(isTaggedSingleNoChecks(this, tag[tLength])){
                        return true;
                    }
                }

                return false;
            }
            else{
                return isTaggedSingleNoChecks(this, tag);
            }
        }

        return false;
    };

    function isTaggedSingleNoChecks(sample, tag){
        const isNegated = tag.charAt(0) == "!";
                
        if(isNegated){
            tag = tag.replace(/^[!]/, "");

            return sample.tags[tag]!==true;    
        }
        else{
            return sample.tags[tag]===true; 
        }
    }
    
    // showing usage
    var sample = new Sample();
    sample.tag('Tag1'); 
    sample.tag('Tag2');
    
    console.log(sample.isTagged('Tag1'));
    console.log(sample.isTagged('Tag3'));
    console.log(sample.isTagged('!Tag2'));
    

这一切都很好,但是我的应用程序在数千个isTagged实例上递归查询Sample数百万次,而我的分析显示这是性能瓶颈。

关于如何提高性能的任何建议?

1 个答案:

答案 0 :(得分:1)

在开始对此进行优化之前,如何首先简化代码并摆脱最明显的奇怪之处(对象而不是Set,无用的正则表达式等)

class Sample {
    constructor() {
        this.tags = new Set();
    }

    tag(...tags) {
        for (let t of tags)
            this.tags.add(t);
    }

    isTagged(...tags) {
        return tags.some(t =>
            (t[0] === '!')
                ? !this.tags.has(t.slice(1))
                : this.tags.has(t)
        )
    }
}

如果这仍然太慢,那么您必须求助于全局对象标签反向索引,例如:

class SetMap extends Map {
    get(key) {
        if (!this.has(key))
            this.set(key, new Set)
        return super.get(key)
    }
}

let tagIndex = new SetMap()


class Sample {
    tag(...tags) {
        for (let t of tags) {
            tagIndex.get(t).add(this)
        }
    }

    isTagged(...tags) {
        return tags.some(t => tagIndex.get(t).has(this))
    }
}

当然,要取消标记(删除标签),尤其是适当的序列化,还需要做更多的工作。

索引本身不会立即加快isTagged的速度,但是会极大地优化查询“查找由X和/或Y标记的对象”。