如何安全地执行操作,然后异步插入.txt文件中的250,000多个单词而不会导致堆栈溢出?

时间:2017-06-02 16:18:17

标签: javascript node.js mongodb mongoose

我想要做的是,在.txt文件中读取,在换行符处切换它们,然后对于构造数组中的每个单词,对单词执行操作(与Word Schema I&匹配) #39; m使用)确定每个单词的字母数,例如"单词(0 A' s,0 B' s,1 W,1 O,1 R,1 D,O Z& #39; s等...),然后将每个Word插入数据库。

这是Word"形状"的猫鼬模式。对于数据库条目(models / words.js)

var restful = require('node-restful');
var mongoose = restful.mongoose;

// MongoDB Schema
var wordSchema = new mongoose.Schema({
    code: String,
    word: String,
    lettersCount: {
        'a': Number,
        'b': Number,
        'c': Number,
        'd': Number,
        'e': Number,
        'f': Number,
        'g': Number,
        'h': Number,
        'i': Number,
        'j': Number,
        'k': Number,
        'l': Number,
        'm': Number,
        'n': Number,
        'o': Number,
        'p': Number,
        'q': Number,
        'r': Number,
        's': Number,
        't': Number,
        'u': Number,
        'v': Number,
        'w': Number,
        'x': Number,
        'y': Number,
        'z': Number
    }
});

// Return model
module.exports = restful.model(
    'Words',
    wordSchema
);

现在,我的数据位于文件dictionaries/words.txt

在名为server.js的主文件中,我正在调用此函数:

populateDictionary();

tasks/populateDictionary.js文件具有以下函数来执行数据库条目:

var populateDictionary = function(dict) {
    Word.remove().exec();
    fs.readFileAsync('dictionaries/words.txt', 'utf8').then(function(data, err) {
        if (err) throw err;
        var dictionary = data.split('\n');
        for (var i = 0; i < dictionary.length; i++) {
            var entry = new Word({
                word: dictionary[i],
                lettersCount: {
                    'a': 0, 'b': 0, 'c': 0, 'd': 0,
                    'e': 0, 'f': 0, 'g': 0, 'h': 0,
                    'i': 0, 'j': 0, 'k': 0, 'l': 0,
                    'm': 0, 'n': 0, 'o': 0, 'p': 0,
                    'q': 0, 'r': 0, 's': 0, 't': 0,
                    'u': 0, 'v': 0, 'w': 0, 'x': 0,
                    'y': 0, 'z': 0
                }
            });
            for (var j = 0; j < entry.word.length; j++) {
                entry.lettersCount[entry.word[j]]++;
            }
            console.log(entry);
            entry.save();
        }
    });
};

所以,我对数据库还是比较陌生的,但是认为那里有一个很好的解决方案,只是不确定是什么......我基本上是在制作一个庞大的调用堆栈,而且它& #39;崩溃了我的电脑。我正在寻找做这种事情的正确方法。谢谢!

3 个答案:

答案 0 :(得分:2)

我建议使用async库。它有许多有用的方法。我在下面使用async.eachLimit将异步操作限制为所提供的数字。

clearDictionary(function(err){
    if(err){
        throw err;
    }
    else{
        populateDictionary();
    }
})

由于remove也是一个io调用,因此它应该在操作结束之前等待,然后再转到下一部分。这就是为什么包裹在上面的clearDictionary。定义如下:

var async = require("async");

var clearDictionary = funtion(done) {
    Word.remove().exec(function(err){
        if(err){
            done(err);
        }
        else{
            done();
        }
    });
}


var populateDictionary = function() {
    fs.readFileAsync('dictionaries/words.txt', 'utf8').then(function(data, err) {
        if (err) throw err;
        var dictionary = data.split('\n');
        async.eachLimit(dictionary, 20, funtion(word, callback){
            var entry = new Word({
                word: word,
                lettersCount: getLetterCountObj()
            });
            countLetters(entry);
            entry.save(function(err){
                if(err){
                    return callback(err);
                }
                else{
                    return callback();
                }
            });
        }, function(err){
            if(err){
                throw err
            }
            else{
                console.log("Dictionary populated!");
            }
        })
    });
};



var getLetterCountObj = function(){
    return {
        'a': 0, 'b': 0, 'c': 0, 'd': 0,
        'e': 0, 'f': 0, 'g': 0, 'h': 0,
        'i': 0, 'j': 0, 'k': 0, 'l': 0,
        'm': 0, 'n': 0, 'o': 0, 'p': 0,
        'q': 0, 'r': 0, 's': 0, 't': 0,
        'u': 0, 'v': 0, 'w': 0, 'x': 0,
        'y': 0, 'z': 0
    }
}


var countLetters = function (entry){
    for (var j = 0; j < entry.word.length; j++) {
        entry.lettersCount[entry.word[j]]++;
    }
}

答案 1 :(得分:0)

我对您使用的确切技术不是很熟悉,但从结构/逻辑流程的角度来看,这可能会有所帮助:

我认为您的问题可能是您在处理之前将整个文件解析到内存中:要实现这一点,您需要一次只处理一个单词。一些快速谷歌搜索引导我到this文章,这使得你似乎可以从你的文件中读取一行,计算它,插入你的形状,然后继续下一个单词,这将防止你吃大量的记忆。

答案 2 :(得分:0)

您可以使用nsynjs按顺序执行IO调用和逻辑的混合。以下是代码需要转换的步骤:

步骤1.将带有回调的慢速函数包装到nsynjs-aware包装器中:

dbWrappers.js:

// wrapper for remove
exports.remove = function (ctx, collection) {
     collection.remove().exec(function(err){
        ctx.resume(err);
     });
};
exports.remove.nsynjsHasCallback = true;

// wrapper for save
exports.save = function (ctx, entry) {
     entry.save(function(err){
        ctx.resume(err);
     });
};
exports.save.nsynjsHasCallback = true;

对于readFileAsync,您可以使用此包装器:https://github.com/amaksr/nsynjs/blob/master/wrappers/nodeFsReadFile.js

步骤2.将您的逻辑编写为同步,并将其置于函数中:

var populateDictionary = function(Word, dbWrappers, readFile) {
    dbWrappers.remove(nsynjsCtx,dict); // use wrapper .remove from above,
                    // nsynjs will wait until callback in the wrapper complete

    var data = readFile(nsynjsCtx, 'path').data; // use wrapper for fs.readFile

    var dictionary = data.split('\n');

    for (var i = 0; i < dictionary.length; i++) {
        var entry = new Word({
            word: dictionary[i],
            lettersCount: {
                'a': 0, 'b': 0, 'c': 0, 'd': 0,
                'e': 0, 'f': 0, 'g': 0, 'h': 0,
                'i': 0, 'j': 0, 'k': 0, 'l': 0,
                'm': 0, 'n': 0, 'o': 0, 'p': 0,
                'q': 0, 'r': 0, 's': 0, 't': 0,
                'u': 0, 'v': 0, 'w': 0, 'x': 0,
                'y': 0, 'z': 0
            }
        });
        for (var j = 0; j < entry.word.length; j++) {
            entry.lettersCount[entry.word[j]]++;
        }
        console.log(entry);
        dbWrappers.save(nsynjsCtx,entry); // use wrapper '.save' from step 1
    }
};

步骤3.通过naynjs:

以同步方式运行该功能
var dbWrappers = require('dbWrappers');
var readFile = require('nodeFsReadFile').readFile;

var populateDictionary = function(Word, dbWrappers, readFile) {
    ....
}

nsynjs.run(populateDictionary,{},Word, dbWrappers, readFile, function(){
    console.log('loading done');
})

参见类似示例https://github.com/amaksr/nsynjs/tree/master/examples/node-mysql(它将任何数字记录插入MySQL)。