Алгоритм определения транзакций среди еженедельных рядов данных?

9

Я пытаюсь разработать небольшой инструмент отчетности (с SQLite Backend). Я лучше всего могу описать этот инструмент как «транзакцию». То, что я пытаюсь сделать, это отслеживать «транзакции» от еженедельного извлечения данных:

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

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

Каждая строка может быть переработана в основном так:
resource_id | resource info | customer_id | customer_info

Образец данных:

10| Title X       | 1 | Bob
11| Another title | 1 | Bob
10| Title X       | 2 | Alice

Цель состоит в том, чтобы упростить составление отчетов о ресурсах, которые не использовались в течение X месяцев (на основе последнего попадания). Существует период хранения, когда ресурсы сохраняются для удобства доступа, если они популярны. Ресурс, который не использовался в течение 18 месяцев, отмечен для долгосрочного архивирования в другом месте.

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

Сварц
источник

Ответы:

1

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

NPV = PV- (PV (CP / T) или новое текущее значение равно текущему значению, умноженному на текущий период (месяцы с момента последней записи), деленному на срок (например, 18 месяцев), когда значение ресурса падает до 0, это чистая текущая стоимость затрачено

Если вы дадите мне lang, вы хотите его, я выложу код здесь в редактировании

J-Босс
источник
Язык не так важен. Ruby или C ++, если бы мне пришлось выбирать. Если вы можете написать алгоритм в HTML 4.0 Strict, вы будете моим героем. Шучу об этой последней части :)
Swartz
Было бы интересно увидеть код. Ruby или C ++. Спасибо.
Swartz
0

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

Пример использования SQL для поиска новых дополнений в таблице: /programming/2077807/sql-query-to-return-differences-between-two-tables

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

Davislor
источник
Лучше, по крайней мере, это решение, ориентированное на данные, но оно все еще излишне
J-Boss
Я использую sqlite на данный момент, так как это легко начать. Можно легко переключиться на MySQL (или PostgreSQL). Если при использовании бэкэнда без SQL ничего не получится, чтобы сделать эту работу еще лучше, я весь в ушах.
Swartz
Ну, я думал в основном, что вы все равно конвертируете его в строки в базе данных . Если вам не нужно запускать его из нескольких процессов одновременно, я не думаю, что вы захотите переключиться на что-то более тяжелое, чем SQLite.
Дэвислор
Нет необходимости в параллельной обработке. Но мне нужно где-то хранить данные о ресурсах. SQL-база данных казалась хорошим выбором, однако ничто не мешает мне загружать данные в любой тип данных для обработки дельт. Все, что я хочу в конце каждого прогона экстракта, - это выяснить, что нового, что осталось прежним, а что исчезло. Я могу выяснить, как обновить записи по мере необходимости из этой информации.
Swartz
После того, как вы проанализировали данные и поместили их в базу данных, возможно, проще написать запрос, чем реализовать алгоритм. Тем не менее, если вы хотите закодировать его, вам нужен алгоритм установки разницы, и в C ++ STL есть реализация, которую вы можете использовать, чтобы сделать это в одной строке, как только вы поместите оба набора данных в контейнер ваш выбор, вероятно Vector.
Дэвислор
0

Альтернативная идея:

  1. Разобрать ваш список транзакций в какую-то структуру данных, например массив. (В C ++, думаю Vector, и в Java ArrayList.)

  2. Выполните запрос в своем бэкэнде SQL, например, SELECT DISTINCT customer_id FROM Transactions ORDER BY customer_idи упакуйте отсортированные отдельные идентификаторы клиентов в набор old. Если вы делаете то же самое с WHEREпредложением, разделяющим старые и новые транзакции, вы можете пропустить шаг 3.

  3. Получите уникальные идентификаторы клиентов из новых обновлений в отдельной структуре данных в отсортированном порядке. Есть пара структур данных, которые вы можете использовать, чтобы получить в структуру данных new. Сортировка вставки в двойной связанный список очень проста, но использование промежуточной хеш-таблицы будет работать близко к линейному времени, или, если вы все равно сортируете исходный массив, получить набор из этого легко.

  4. Возьмите разницу new- oldиспользуйте стандартную библиотеку вашего любимого языка. Ваш любимый язык имеет этот алгоритм в своей стандартной библиотеке?

Другие вещи, которые вы хотите сделать, это определенно SQL-запросы после обновления базы данных транзакций.

Примечание на шаге 3: рассмотрите характер ваших данных. Предположим, что в вашем текстовом файле перечислены заказы в хронологическом порядке, и в обычную неделю есть много новых клиентов, которые получают новые customer_idв порядке возрастания. Предположим, что большинство других заказов поступает от небольшого числа постоянных постоянных клиентов с меньшим customer_id. Тогда ваши входы уже в основном отсортированы. Сортировка вставки, в которой вы пытаетесь вставить низкий customer_idв начале двойного связанного списка и высокий customer_idв конце, в этой ситуации будет хорошо работать на практике.

Davislor
источник
1
Меня больше интересуют новые / такие же / обновленные ресурсы, а не клиенты. Но да, идея была бы той же.
Swartz
0

Как я понял из вашего вопроса, у вас действительно есть resource_id (+ info) и «список» клиентов (id + info).

Таким образом, вы можете легко хранить список клиентов для каждого ресурса и проверять последний узел в каждом списке на ресурсе (чтобы узнать время последней операции; вам просто нужно добавить поле даты для вашего клиента в коде)

Я не знаком с SQL, поэтому я привожу свой пример с HashMapи List, но я уверен, что это та же идея: HashMap <Resource, List<Customer>>когда Resourceдолжен содержать resourceID в качестве ключа и Customerдолжен содержать идентификатор клиента, информацию и дату операции.

С этой идеей вы можете легко узнать время последней операции и можете изменить любой ресурс (добавить \ удалить ресурс \ клиент).

AsfK
источник
0

Если вы используете базу данных SqLite, если вы добавите дату пакета также в качестве столбца таблицы,

10| Title X       | 1 | Bob    | 2015-03-01
11| Another title | 1 | Bob    | 2015-03-01
...............................
10| Title X       | 1 | Alice  | 2015-03-05

было бы довольно просто использовать SQL, чтобы получить ресурсы, не использовавшиеся за последние X дней

Select distinct r.ResourceID from Resources r
where not exists (SELECT julianday('now') - julianday(r.DateUpdated)) < X

Я не проверял SQL, но он должен дать вам представление

Низко летящий пеликан
источник
0

Из исходного поста звучит так, как будто у загружаемых данных нет поля для указания даты / времени транзакции, и я предполагаю, что файл принимается часто по расписанию, например ежедневно, ежечасно и т. Д.

Я бы справился с этим, добавив столбец отметки времени SQL, который либо генерируется автоматически на уровне базы данных, либо с помощью кода, который извлекает данные и вставляет их в базу данных. Затем вы помещаете индекс в этот столбец отметки времени и покончите с этим. Пусть механизм БД сделает свою работу эффективной, чтобы ответить на вопрос «сколько транзакций не произошло с этого времени» или «сколько между этим временем и тем временем».

Затем вы планируете задание для запроса и рассчитываете различия, по которым вы хотите отчитаться. Транзакции, которые являются «новыми», - это транзакции, которые не имеют записей в БД до даты, которую вы запрашиваете «новые с тех пор». Старые записи - это те, которые не имеют транзакций с даты закрытия.

Томас Карлайл
источник
-2

Разве это не то, для чего нужны HashTables? Если все, что вы хотите сделать, это вести учет того, какие ресурсы использовались в последние месяцы, и удалять ресурсы, к которым не обращались в течение последних 18 месяцев, тогда вы можете использовать HashTable, где Key - это resource_id, а значение - это дата последнего доступа.

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

Адриан Бузеа
источник
Зачем нужен HashTable, если я храню вещи в базе данных? Я могу сделать обновления для записей БД. Меня больше интересует случай: возьмите два набора данных, выясните различия (что добавлено, осталось прежним, удалено) между двумя наборами. Как техника HashTable поможет найти новые и «удаленные» записи?
Шварц
Если таблицы индексируются в базе данных, то они в основном также являются закулисными таблицами HashTable. Если у вас есть 2 таблицы, каждая из которых представляет набор данных, вы можете получить новые и удаленные записи, выполнив несколько внешних объединений. См. Это для справки: i.stack.imgur.com/pxUO3.png . Убедитесь, что у вас есть индексы для столбца resource_id, и это должно быть довольно быстро. Если бы вам пришлось реализовать это с нуля, то я думаю, что HashTables все равно был бы подходящим вариантом, поскольку вы можете выполнять поиск / вставку / удаление за O (1) амортизированное время. Не могу придумать более эффективный способ сделать это.
Адриан Бузеа
3
Существуют более совершенные структуры данных, которые справляются со старением без дополнительных этапов их преобразования в хеш-таблицу.
Хотите упомянуть некоторые?
Адриан Бузеа
@ Снеговик - Я бы хотел еще несколько раз оценить это, я просто решительно согласен с этим комментарием
J-Boss