Как написать задачу Rake для импорта данных в приложение Rails? - PullRequest
9 голосов
/ 27 июля 2010

Цель: Использование задачи CRON (или другого запланированного события) для обновления базы данных с ночным экспортом данных из существующей системы.

Все данные создаются / обновляются / удаляются в существующей системе. Веб-сайт напрямую не интегрируется с этой системой, поэтому приложение rails просто должно отражать обновления, которые появляются в экспорте данных.

У меня есть .txt файл из ~ 5000 товаров, который выглядит следующим образом:

"1234":"product name":"attr 1":"attr 2":"ABC Manufacturing":"2222"
"A134":"another product":"attr 1":"attr 2":"Foobar World":"2447"
...

Все значения представляют собой строки, заключенные в двойные кавычки ("), разделенные двоеточиями (:)

Поля:

  • id: уникальный идентификатор; буквенно-цифровой
  • name: название продукта; любой персонаж
  • атрибут столбцы: строки; любой символ (например, размер, вес, цвет, размер)
  • vendor_name: строка; любой персонаж
  • vendor_id: уникальный идентификатор поставщика; Числовой

Информация о поставщике не нормализуется в текущей системе.

Каковы лучшие практики здесь? Можно ли удалять таблицы продуктов и поставщиков и перезаписывать новые данные в каждом цикле? Или лучше только добавлять новые строки и обновлять существующие?

Примечания:

  1. Эти данные будут использоваться для генерации Orders, которая будет сохраняться при ночном импорте базы данных. OrderItems необходимо будет подключить к идентификаторам продуктов, указанным в файле данных, поэтому мы не можем полагаться на то, что первичный ключ с автоинкрементным увеличением будет одинаковым для каждого импорта; уникальный алфавитно-цифровой идентификатор необходимо будет использовать для присоединения products к order_items.
  2. В идеале, я бы хотел, чтобы импортер нормализовал данные поставщика
  3. Я не могу использовать ванильные операторы SQL, поэтому я полагаю, что мне нужно написать задачу rake, чтобы использовать синтаксис в стиле Product.create(...) и Vendor.create(...).
  4. Это будет реализовано на EngineYard

Ответы [ 3 ]

14 голосов
/ 27 июля 2010

Я не буду удалять таблицы продуктов и поставщиков в каждом цикле. Это приложение для рельсов? Если так, то есть несколько действительно хороших помощников ActiveRecord, которые вам пригодятся.

Если у вас есть модель активной записи Продукта, вы можете сделать:

p = Product.find_or_initialize_by_identifier(<id you get from file>)
p.name = <name from file>
p.size = <size from file>
etc...
p.save!

find_or_initialize будет искать продукт в базе данных по указанному вами идентификатору, и если он не сможет его найти, он создаст новый. Очень удобно делать это таким образом, что ActiveRecord будет сохранять в базу данных только в том случае, если какие-либо данные были изменены, и автоматически обновляет любые поля отметок времени, которые у вас есть в таблице (updated_at) соответственно. Еще одна вещь, поскольку вы будете искать записи по идентификатору (идентификатору из файла), я обязательно добавлю индекс по этому полю в базе данных.

Чтобы выполнить задачу rake, я бы добавил файл rake в каталог lib / tasks вашего приложения rails. Мы назовем это data.rake.

Внутри data.rake это будет выглядеть примерно так:

namespace :data do
  desc "import data from files to database"
  task :import => :environment do
    file = File.open(<file to import>)
    file.each do |line|
      attrs = line.split(":")
      p = Product.find_or_initialize_by_identifier(attrs[0])
      p.name = attrs[1]
      etc...
      p.save!
    end
  end
end

Чтобы вызвать задачу rake, используйте «rake data: import» из командной строки.

0 голосов
/ 27 июля 2010
  • Создайте задание импортера для граблей
  • Разбор файла построчно с помощью Faster CSV или vanilla ruby, например:

file.each do | line | products_array = line.split (":") конец

  • Разбить каждую строку на ":" и вставить в хеш
  • Используйте find_or_initialize для заполнения вашей базы данных, например:

    Product.find_or_initialize_by_name_and_vendor_id ("foo", 111)

0 голосов
/ 27 июля 2010

Поскольку продукты на самом деле не меняются так часто, лучший способ, который я бы увидел, - это обновлять только те записи, которые меняются.

  1. Получить все дельты
  2. Массовое обновление с помощьюодин оператор SQL

Если у вас есть код нормализации в моделях, вы можете использовать Product.create и Vendor.create, иначе это будет просто перебор.Также обратите внимание на вставку нескольких записей в одну транзакцию SQL, это намного быстрее.

...