2015-01-15 4 views
0

Я работаю над небольшим проектом, который постепенно расширяет список ссылок, а затем обрабатывает их через очередь. Существует вероятность того, что ссылка может быть введена в очередь дважды, и я хотел бы отслеживать свой прогресс, чтобы я мог пропустить все, что уже было обработано. Я оцениваю около 10 тыс. Уникальных ссылок в лучшем случае.Какова самая эффективная структура данных Ruby для отслеживания прогресса?

Для больших проектов я бы использовал базу данных, но это кажется излишним для количества данных, с которыми я работаю, и предпочел бы какое-то решение в памяти, которое потенциально может быть сериализовано, если я хочу сохранить прогресс во всех прогонах.

Какая структура данных наилучшим образом соответствует этой потребности?

Обновление: Я уже использую хэш для отслеживания тех ссылок, которые я завершил. Это самый эффективный способ сделать это?

def process_link(link) 
    return if @processed_links[link] 
    # ... processing logic 
    @processed_links[link] = Time.now # or other state 
end 
+0

Используйте хэш или набор. У вас может быть только один экземпляр ключа в Hash. Набор построен на хэш-ключах, и вы получаете аналогичное поведение. –

+0

Еще одна вещь, о которой стоит подумать, нужно ли отслеживать прогресс в отношении сбоев/сбоев/перезапусков? Если это так, вы не можете вообще использовать отслеживание в памяти и, вероятно, должны использовать базу данных. –

ответ

1

Если вы не обеспокоены памятью, просто используйте хэш для проверки включения; вставка и время поиска - это O (1) средний случай. Сериализация проста (класс маршала Ruby должен позаботиться об этом для вас, или вы можете использовать такой формат, как JSON). Ruby's Set - это массивный объект, который поддерживается хешем, поэтому вы можете просто использовать его, если вы так склонны.

Однако, если память является проблемой, то это большая проблема для Bloom filter! Вы можете достичь установленного тестирования включения в постоянное время, и фильтр использует значительно меньше памяти, чем хэш. Компромисс - это фильтры Bloom, которые вероятностны - вы можете получить ложные включения.Вы можете исключить вероятность большинства ложных срабатываний с нужными параметрами цветения фильтра, но если дубликаты скорее исключение, чем правило, вы могли бы реализовать что-то вроде:

  1. Проверьте наличие множества включения в Bloom фильтре [O (1)]
  2. Если фильтр цветения сообщает, что запись найдена, выполните проверку входных данных O (n), чтобы увидеть, был ли этот элемент найден в массиве входных данных до этого момента.

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

https://github.com/igrigorik/bloomfilter-rb - это реализация фильтра Bloom, которую я использовал в прошлом; он работает красиво. Также есть фильтры Bloom с поддержкой Redis, если вам нужно что-то, что может выполнять отслеживание и тестирование членства в нескольких экземплярах приложения.

+0

Спасибо, это всего лишь информация, которую я искал. Я не рассматривал фильтр Bloom, так как обычный случай гарантированно не существует, потенциально ложный положительный для проверки включения. Это дополнение проверки O (n), когда вы получаете удар, - это приятное легкое дополнение. –

1

Как насчет Set и преобразовать ваши ссылки в объект значения (а не объект ссылки), такой как Structs. Создав объект значения, Set сможет обнаружить его уникальность. Альтернативно, вы можете использовать хэш и хранить ссылки своим ПК.

+0

«Хэш» выглядел наиболее очевидным, но я не уверен, насколько хорошо хеширование ключей будет содержать более 10 тыс. Вставок, как памяти, так и обработки. –

+0

Ключевое хеширование будет прекрасным. Лучший вопрос: как Ruby обрабатывает ключи 10K и связанные значения? Может быть, достойная база данных будет лучше? –

+0

Запуск ранней версии моего скрипта закончил тем, что дал гораздо больше ссылок, чем ожидалось. Когда я ударил 300k в объекте 'Queue' и используя объект Hash для отслеживания всех видимых ссылок, я решил, что пришло время использовать БД для отслеживания пробегов и сбоев. Кроме того, я был приятно удивлен тем, что в Ruby-процессе использовалось только около 15 МБ оперативной памяти, и на моем процессоре почти не наблюдалось (большую часть времени было потрачено на блокировку в сети). –

1

Структура данных может быть хэш:

current_status = { links: [link3, link4, link5], processed: [link1, link2, link3] } 

Чтобы отслеживать прогресс (в процентах):

links_count = current_status[:links].length + current_status[:processed].length 
progress = (current_status[:processed].length * 100)/links_count # Will give you percent of progress 

Для обработки ссылок:

  • push любая новая ссылка вам необходимо обработать до current_status[:links].
  • Используйте shift, чтобы взять с current_status[:links] следующую ссылку для обработки.
  • После обработки ссылки, push его current_status[:processed]

EDIT

Как я понимаю (и понимаю ваш вопрос), логика для обработки ссылок будет:

# Add any new link that needs to be processed to the queue unless it have been processed 
def add_link_to_queue(link) 
    current_status[:to_process].push(link) unless current_status[:processed].include?(link) 
end 

# Process next link on the queue 
def process_next_link 
    link = current_status[:to_process].shift # return first link on the queue 
    # ... login process the link 
    current_status[:processed].push(link) 
end 

# shift method will not only return but also remove the link from the original array to avoid duplications 
+0

Используя как ссылки, так и обработанные, мне нужно будет проверить наличие ссылки в двух массивах, каждая из которых через ##include ?, которая, я считаю, реализована как простая операция сканирования. Время обработки будет складываться быстро, так как я начал добавлять множество ссылок на каждый из этих массивов. –

+0

Кроме того, я уже использую 'Queue' для обработки фактической части обработки. Я просто ищу эффективный способ отслеживания записей, которые я завершил, поэтому я не обрабатываю их снова, если они вернутся в очередь. –

+0

@SethV Я только что отредактировал свой ответ. Как я вижу, вам нужно только проверить существование в одном массиве (массив обработанных ссылок). Проверьте это и скажите мне, может быть, я не понимаю, что вы хотите. – Alfonso

Смежные вопросы