Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 05.09.2015, 12:27
Новичок на форуме
Отправить личное сообщение для Nicolas Bourbaki Посмотреть профиль Найти все сообщения от Nicolas Bourbaki
 
Регистрация: 05.09.2015
Сообщений: 2

Как лучше найти и удалить одну строку в очень большом файле
Примерно год назад собеседовался с немцами, на одном из этапов дали это легкое тестовое задание. Мое решение их устроило, но позже уже третье собеседование по алгоритмам и теории я завалил капитально.

Наткнулся на него случайно, разгребая старую почту. Оцените мое решение, кто в теме. Как часто спрашивают во всяких бизнес линчах "Стоит продолжать развиваться в этом направлении или забыть?"

Условие:

Представьте, что вы работаете в компании, которая помогает американским фирмам импортировать свои товары для продажи в ЕС. Давайте представим, что каждый заказ может быть представлен в виде кортежа(tuple по англ, надеюсь правильно перевел) - (orderId, companyName, customerAdress, orderedItem).

Пример того, как может выглядеть такой набор данных в файле:

001, SuperTrader, Steindamm 80, Macbook
002, Cheapskates, Reeperbahn 153, Macbook
003, MegaCorp, Steindamm 80, Book "Guide to Hamburg"
004, SuperTrader, Sternstrasse 125, Book "Cooking 101"
005, SuperTrader, Ottenser Hauptstrasse 24, Inline Skates
006, MegaCorp, Reeperbahn 153, Playstation
007, Cheapskates, Lagerstrasse 11, Flux compensator
008, SuperTrader, Reeperbahn 153, Inline Skates

Нужно реализовать:

1) Отобразить все заказы конкретной компании
2) Показать все заказы по конкретному адресу
3) Удалить какой-то заказ по его OrderId
4) Отобразить самые популярные товары по убыванию


Мое решение (все лишнее вроде server.js, routes.js и тд опущены, ниже только сам контроллер):

// app/controller.js

var fs     = require('fs'),
    byline = require('byline');

function find(position, value, next) {

    var content,
        temp,
        data = new Array();

    value = value.trim();

    var stream = byline(fs.createReadStream('sample', {encoding: 'utf8'}));
    stream.on('readable', function() {

        while ((content = stream.read()) !== null) {
            content = content.split(/\r?\n/);
            content.forEach(function(item) {
                if (!item) {
                    return;
                }

                temp = item.split(',');

                // if there are some wrong format data
                // for example delivery address with comma "Reeperbahn, 153"
                // we can do nothing and just skip this broken line
                if (temp.length != 4) {
                    return;
                }

                if (temp[position].trim() == value) {
                    data.push(temp);
                }
            });
        }
        
    });

    stream.on('end', function() {
        next(null, data); return;
    });
}

function getTopSellers(req, next) {

    var content,
        temp,
        data = {},
        companies = new Array();

    var stream = byline(fs.createReadStream('sample', {encoding: 'utf8'}));
    stream.on('readable', function() {

        while ((content = stream.read()) !== null) {
            content = content.split(/\r?\n/);
            content.forEach(function(item) {
                // empty line?
                if (!item) {
                    return;
                }

                temp = item.split(',');

                if (temp.length != 4) {
                    return;
                }

                // temp[3] is a product name
                if (data[temp[3]]) {
                    data[temp[3]] += 1;
                } else {
                    data[temp[3]] = 1;
                }

                // if not ajax, then create also companies list
                if (!req.xhr) {
                    if (companies.indexOf(temp[1]) < 0 && typeof temp[1] != undefined) {
                        companies.push(temp[1]);
                    }   
                }
                
            });
        }
        
    });

    stream.on('end', function() {
        var top = new Array();
        var temp = {};

        for(var key in data) {
            temp[key] = data[key];
            top.push(temp);
            temp = {};
        }
        top.sort(compare);
        next(null, top, companies); return;
    });
}

function deleteOrder(id, next) {

    var content,
        temp,
        data = '',
        storage,
        found = false;

    // we are blocking the whole process, while deleting an order
    // to avoid loosing of data, if new orders appearing very quickly
    content = fs.readFileSync('sample', {encoding: 'utf8'});

    content = content.split(/\r?\n/);
    content.forEach(function(item) {

        storage = item;
        temp = item.split(',');

        if (temp.length != 4) {
            return;
        }

        if (temp[0].trim() == id) {
            found = true;
        } else {
            data += storage + '\n';
        }
    });

    if (found) {
        fs.writeFileSync('sample', data);
        next(null, "ok"); return;
    } else {
        next(null, "error"); return;  
    }
}

function compare(a,b) {
    for (var a_key in a) {
        for (var b_key in b) {
            if (a[a_key] > b[b_key])
                return -1;
            if (a[a_key] < b[b_key])
                return 1;
            return 0;
        }
    }
}

module.exports.getTopSellers    = getTopSellers;
module.exports.find             = find;
module.exports.deleteOrder      = deleteOrder;


Интересует в принципе общая оценка решения, но есть один главный вопрос. Как в таком случае нужно и вообще правильно делать удаление заказа? В моем решении я считываю по строке из файла и затем, после прохода по всему файлу, перезаписываю его полностью без той строки, в которой нужно было найти orderID и удалить. Для этого мне конечно же приходится блокировать весь процесс, чтобы параллельно не могло быть другой записи в файл из Ноды, чтобы избежать перезаписи \ потери данных. Для небольших файлов оно еще работает, но что если этот файлик с заказами будет 10GB, например? Скажем это все заказы текущего месяца, миллионы их. Стоит об этом вообще париться, или так вряд ли бывает и задача не корректна? Как лучше решить задачу для файла с 10GB данных, куда каждую минуту пишутся новые заказы, отменяются старые и тд (Амазон, например).

Последний раз редактировалось Nicolas Bourbaki, 09.09.2015 в 14:20. Причина: Изменен заголовок
Ответить с цитированием
  #2 (permalink)  
Старый 18.09.2015, 00:05
Аватар для khusamov
Соединяю Node.js и Ext JS
Отправить личное сообщение для khusamov Посмотреть профиль Найти все сообщения от khusamov
 
Регистрация: 25.06.2009
Сообщений: 1,033

похоже в случае 10 Гб нужно уже базу данных применять, а не парится делать аналог СУБД для файла)))
__________________
Хусамов Сухроб, Москва, khusamov@yandex.ru
Мой JS-стек: Sencha ExtJS 6, Node.js, TypeScript.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Оцените мое детище veterok2308 Ваши сайты и скрипты 6 19.02.2013 20:34
Решение задания: супер обработка клика pavluxa09 Events/DOM/Window 19 08.01.2010 14:54