Как можно безопасно выполнить операции, а затем асинхронно вставить более 250 000 слов из файла .txt, не вызывая переполнение стека?

1

То, что я пытаюсь сделать, читается в.txt файле слов, разрезает их на новые строки, а затем для каждого слова в построенном массиве выполняет операции над словом (которое соответствует используемой схеме Word) определите количество букв для каждого слова, например, для слова (0 A, 0 B, 1 W, 1 O, 1 R, 1 D, OZ и т.д.), а затем вставьте каждое 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, я 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();
        }
    });
};

Итак, я довольно новичок в базах данных, но думаю, что там есть хорошее решение, просто не знаю, что... Я в основном создаю огромный стек вызовов, и он разбивает мой компьютер. Я ищу правильный способ сделать это. Благодарю!

Теги:
mongoose

3 ответа

2
Лучший ответ

Я бы предложил асинхронную библиотеку. Он имеет много полезных методов. Я использовал async.eachLimit, ниже которого ограничивает операции async предоставленному числу.

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]]++;
    }
}
0

Вы можете последовательно исполнять смесь вызовов IO и логики с помощью nsynjs. Вот шаги, которые необходимо преобразовать код:

Шаг 1. Оберните медленные функции с помощью обратных вызовов в обертки, совместимые с nsynjs:

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).

0

Я не очень хорошо знаком с точными технологиями, которые вы используете, но с точки зрения структуры/логики, может быть, это поможет:

Я думаю, что ваша проблема может заключаться в том, что вы разбираете весь файл в памяти перед обработкой: это много, чтобы удержать, когда на самом деле вы просто хотите обрабатывать одно слово за раз. Некоторые быстрые Googling приводят меня к этой статье, из-за которой вам кажется, что вы можете прочитать строку из вашего файла, считать ее, вставить свою фигуру и перейти к следующему слову, которое должно помешать вам съесть тонну памяти.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню