<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55
global $wpdb2;
global $failure;
global $file_hist;
///// echo '<H2><b>Старт загрузки</b></H2><br>';
$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
///// echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}
$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
///// echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}
/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
///// echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
///// echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist); ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7]; ////получаем размер файла
$m_mtime_file=$masiv_data_file[9]; ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file
///// echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
///// echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
///// echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);
if ($results)
{ foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));
////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
///// echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
///// echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}
////загружаем данные
$table='vin_history'; // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация // (путь от корня web-сервера)
$delim=';'; // Разделитель полей в CSV файле
$enclosed='"'; // Кавычки для содержимого полей
$escaped='\
хранение этой таблицы недействительных паспортов в oltp базе — крайне не профессионально и повод для увольнения.
и мвд давно уже выкладывает файлы обновлений. так что полное пересоздание не требуется.
(1)
Напишите об этом в Аудит-Эскорт. Как я и сказал в конце статьи, есть вариант вынести таблицу за пределы БД, это также есть в планах. Принципиально на технику решения 1 и 2 подзадач это не повлияет, а значит, ничуть не уменьшает полезность описанных в статье приёмов. Но в настоящий момент для экономии времени решил использовать имеющийся РС, чтобы не переделывать обращения к нему в типовых запросах на проверку, которые написаны разработчиком конфигурации «Управление МФО и КПК».
когда мвд не выкладывало обновлений, я их генерировал сам: сравнивал длины файлов , обрезал новый до длины старого, сравнивал хэши,
если совпадали то догружал новый кусок. а загрузку большого файла разбивал на мелкие по 10 мегабайт. выравнивал текст по границе записей, и загружал в несколькими фз .
(3)
Про генерацию файлов сравнения и дозагрузку информацию в интернете встречал. А вот про то, что мвд отдельно выкладывает обновления не видел. Это открытая информация? Может, ссылочкой поделитесь?
простите. про отдельные обновления обманул (спутал с каким-то другим классификатором типа фиас.)
а файл list_of_expired_passports вырос в размере с 300 мегабайт до 400.
Я бы поместил таблицу в отдельную базу ms sql и обращался бы к ней через внешний источник.
(6)
Не спорю — это отличный вариант. Но пока совсем не припёрло, держим конфигурацию на полной поддержке. Все доработки вносятся через расширения и внешние отчеты/обработки. К сожалению, механизм расширений пока не дошёл до того уровня, чтобы добавлять в него свои внешние источники данных. Поэтому этот вариант у себя я не стал использовать.
(7) Ну это уже фобия какая-то. Достаточно только для корня конфигурации поставить «редактируется с сохранением поддержки», а все остальные типовые объекты оставить на «..не редактируется».
(9)
Примерно об этом я и писал в последнем абзаце статьи. Спасибо, что раскрыли тему чуть подробнее и набросали варианты.
Сам склоняюсь к последнему варианту. Осталось всего ничего: найти время, абстрагироваться от 1С, изучить по верхам необходимые технологии и реализовать такой сервис.
Задача очень громоздкая для 1с. Для данной задачи необходимо поднимать отдельный сервак с SQL или.подключать к API проверки паспортов сторонних разработчиков. Как вариант здесь можно подключить API passport.bg-c.РУ( НЕ реклама!)
Решили подобную задачу написав свой API сервис на python c БД на postgres. Скорость обновления базы 5 часов. Обновляемся вечером в 20-00, т.к до 18-30 обновляется файл источника.
PS. Базу нужно полностью обновлять, т.к. в ней бывают ошибочно введены паспорта, которые в дальнейшем удаляются.
(11)(12)(13)
Именно об этом и рассказывается в статье. Поэтому обновление базы вынесено непосредственно в SQL.
В принципе, время приемлемое. Но на своих мощностях с MS SQL мне удалось добиться меньшего времени обновления (1 час).
Такие мысли тоже посещали мою голову. Не даром же МВД выгружает их целиком.
У нас 1 процессорный сервер 2004 года выпуска на Linux с докером сервиса 1с + докер postgress и докер с сервисом проверки паспортов, поэтому скорость обновления базы 5 часов. Если иметь современную 2- процессорную систему, то скорость обновления базы будет в разы быстрее.
Решал данную задачу на С++ — база грузится 16 секунд, поиск номера за О(1). Все это барахло с базами данных — для тех, кто не умеет программировать. На 1С аналогичный алгоритм работает 15 минут. И никаких суток, и никакого питона и 5 часов. Просто нужно мозг включить.
(16)
Поделитесь решением, пожалуйста.
(17)
А сколько Вы готовы за него заплатить?
(18) Ну мне интересен принцип, хотя бы даже в общих чертах, нежели конкретная реализация. Глядишь и программировать научусь и мозг включится )
(19)
У нас есть решение по ФЗ115 — там как раз проверка паспортов производится за секунды, и загрузка туда осуществляется в районе 15 минут. А суть — в организации данных.
(20)
Так не расскажите сообществу как у Вас в этом процессе данные организованы? Это же очень интересно.
(22)
Ах, блин, прям нагоняете саспенс. Любопытство растет и растет. Сколько стоит Ваша консультация по данной теме?
(23) только в личку.
Мне буквально недавно поставили задачу и «мы-же документаций не читаем» и на инфостарт не полез. В общем мой велосипед оказался достаточно производительным. Делюсь.
1. с помощью wget идет загрузка
2. Была поднята база данных на скуле. Дальше с помощью пакета SSIS (dtx) был сделан скрипт который из csv грузит данные в таблицу. На тормозном сервере процесс занимает 10 минут. Это в разы быстрее ибо база чистится truncate и кладутся данные bulk insert-ом (воторое не проверял, но скорость поражает)
1-й пукнт ограничен интернетом. Во втором пункте больше времени занимает распаковка данных чем их загрузка:)
3. Дальше можно либо работать в рамках своих знаний — либо через внешний источник данных либо прямой sql, но это для проверки одного, а что нужно сделать для отчета по всем?
4. Отчет с получением данных из внешнего источника мега медленный (все-таки 120 миллионов записей было на момент написания комментов). Я сделал так. Создал таблицу с данными физиков (тех, кого проверяем). С помощью аналогичного пакета из пп 2 грузанул данные напрямую из 1С-ной базы. Дальше сделал view которая состоит из inner join-а двух таблиц — паспорта и данные 1С. И данные из этой view можно опять же взять напрямую из внешнего источника, а можно и прямым sql. Я был удивлен. пакет по импорту данных клиентов на массиве 30 тысяч отрабатывает за 2 секунды. Запрос на этом массиве 15 секунд. Если думаете, что тут мега железо, то для примера могу сказать. Я сначала хотел построить кластерный индекс по серии и номеру. Так вот. Ждал 4 часа и не дождался:) Железо и винты виртуальные и крайне тормознутые. Тоесть получение отчета вместе со всеми подготовками и переносами данных укладывается в одну минуту.
1й и 2-й пункты по подготовке и обновлению данных укалываются в один bat файл, не требуют программирования на 1С, c++, python-е итп, и судя по комментам, работают гораздо быстрее 🙂
(25)
На С++ все паспорта грузятся на моем домашнем Ryzen 1600 1 минута 11 секунд (распаковка — основное время — библиотека zlib, чтение — 4 секунды, упаковка базы — остальное время, в итоге 300 метров превращается в 30 метров). Памяти процесс кушает 400 МиБ. Проверка в итоге за О(1), т.е. 120кк паспортов проверяется за время меньше, чем их чтение (< 4 секунды). Так что не сказал бы я, что содержание базы данных в 10 гигабайт (а в столько примерно разворачивается данные 120кк паспортов, если с индексами) — это отличное решение. Мы тоже сначала в скул грузили, но пришли к выводу, что оное никому не нужно.
ЗЫ: Сишный алгоритм чтения, реализованный на 1С, у коллеги на i9-9900K (4,6GHz на все ядра в таскменеджере) работает примерно за 430 секунд безо всякой СУБД. Но, конечно, видя такую разницу (4 сек против 430 сек) понимаешь, на сколько тормознута 1С в части интерпретатора.
(26) Я ничуть не умоляю того, что нормальный алгоритм на сях способен скушать все быстро. Я про то, что мелкомягкие тоже умеют делать все быстро и с помощью встроенных механизмов задача решается за считанные минуты. И мне нужен был отчет. И если даже проверка по одной записи будет занимать 0.1 сек то массив в 30к клиентов будет обрабатываться 50 минут (3к сек), а чтобы все отработало шустро то нужно изобрести собственную субд которая умеет делать join и всякие плюшки около него:)) но возможно отработает быстрее.
1С (да простят меня создатели) вообще нельзя рассматривать как средство построения алгоритмов анализа. Только сбор. А анализ запросами.
(1) Тогда в первую очередь увольняться должны пойти 1С ники которые хранят адресный классификатор в БД, который тоже плоская таблица по сути. А более профессионально это как? Поднять под такую задачу отдельный сервер с mongoDB или прикрутить ellasticSearch туда?
(27)
1C просто охрененно медленный интерпретатор, но, поверьте, для большинства алгоритмов анализа не нужно море данных. Я пробовал партионный учет реализовать без СУБД — работает этак на порядок быстрее (даже на два порядка).
СУБД — это механизм обеспечения перситентности состояния системы. Для обеспечения надежности необходимо сбрасывать кеш при фиксации транзакций на диск. Для ускорения выборки нужно создавать и хранить индекс. Ну и так далее..
Для проверки паспорта не нужны джоины — нужен GET по ключу — паспорту. Затянуть в тот же REDIS (NoSQL) базу паспортов не составляет труда — пять минут. И это, в принципе, правильный подход, т.к. нам не нужен здесь какой-то реляционный механизм. Проверить на нем паспорт со скоростью 2кк/сек (т.е. 120кк за минуту) — вполне посильно любому современному процессору. Использовать для этого MS SQL — это как пушкой по воробьям.
А реализация механизма Key -> Value на 1С для такого типа данных — это вообще примитивный алгоритм. И он даже на движке 1С работает не медленнее, чем MS SQL (если с умом подойти).
(28)
Человек говорит о том, что bigdata в виде постоянно обновляемого классификатора в базе с OLTP нагрузкой (много маленьких запросов на чтение и запись) — это полный бред. И я с ним на 100% согласен.
ЗЫ: Вот тупо самый простой алгоритм, который будет быстрее, чем загрузка этой всей хрени в БД: 1. Берем исходный файл с паспортами и пишем его в файлы по сериям. В итоге у нас будет максимум 1000 файлов с не более чем лямом недействительных паспортов. 2. Читаем все паспорта, которые нужно проверить, группируем по сериям. 3. Обходим по сериям. Если файл с серией есть — смотрим внутрь для каждого (подгрузить файл в таблицу значений вообще не проблема, особенно если файл сохранялся как ЗначениеВФайл). Предположу, что скорость проверки будет не ниже, чем эта вся возня с СУБД. Также можно атомарно обновлять данные для проверки путем развертывания в новый каталог и последующего переименовывания нового каталога в старый (или можно дату в каталоге указывать, тогда система будет его юзать по дате). Ну и хранилище значений со сжатием можно пользовать — позволит сэкономить место на диске. А если раздербаниватель исходного файла на файлы серий написать на С, то скорость будет равна примерно скорости записи на диск — можно на каждую серию свой файл открыть.
(29) Согласен что можно. Но я не верю, что написанный алгоритм с тестами итп был написан быстрее чем за 2-3 часа. Там скорее всего минимум день суммарно ушел. А я про то, что можно сделать быстро и результативно.
Я думаю, что именно под данную структуру данных вообще можно алгоритм поиска гораздо быстрее чем О(1). Если заморочиться.
Мой спич про простоту реализации. Изучить Си для реализации, если его не знаешь или еще что то, мне кажется сложным. Если ты только 1С-ник.
(31)
Быстрее чем О(1) в принципе быть не может, т.к. это самое О(1) говорит, что операция производится за единичное вычисление. Нельзя вычислить меньше раз, чем единица.
А по поводу С, то не нужно никакого С — достаточно прочитать в что-то номер паспорта и сохранить в файл с именем <серия>. Можно так:
Показать
А проверку так:
Показать
Все, на выходе в БылаСерия список серий, а внутри массив номеров, которые обнаружены. Сдается мне, что эта штука будет работать не сильно дольше скульного запроса, а реализуется вот за 5 минут (у меня вот столько ушло на написание сообщения этого).
Ну и, ежу понятно, результат запроса нужно упорядосить по сериям.
(32) Да, перепутал O(n) и O(1) 🙂
Вот стало интересно. Что то мне кажется, что данный алгоритм на файле размером 1.4 гига, умрет.
Отпишусь:)) Интрига!)
(33) ну ежу понятно, что в (32) не О(1), а как-то типа О(n/10000) как максимум. Но тоже не плохо )))
ЗЫ: а умрет может быть из-за того, что одновременно 10к файлов открыть будет непросто венде. Хотя… Вроде на NT-ном ядре современные венды это умеют.
(34) Прогнал я тест. Код проверки я изменил. В выборке сортировал по серии и просто открывал по очереди тем самым не кушал память и исключил рандомное чтение, а поиск по сути свелся на поиск в памяти по строке. ПО скорости получилось 90 секнуд против 5ти (это если не актуализировать таблицу клиентов в скульной базе, иначе 15 секунд выходит) на массиве в 30к клиентов.
Обработка тоже уложилась гдето в 40 минут. В общем результат достаточно живой. Однако всеравно на доводку ушло время. И если скуль есть, то всеравно считаю изобретение велосипедов лишним. Проигрыш в скорости выполнения не считаю критичным, ибо это не те запросы которые выполняются часто. А вот время создания и тетсирования с использованием уже готовых механизмов скуля и того-же wget для скачки, существенно меньше. И все работает из коробки:) К примеру, как выяснилось спустя 20 минут, что вылезают левые ошибки доступа к файлу. Пока потестил и понял, что в исходном файле местами в серии лежит мусор и файлы со служебными символами в имени не создаются (что логично, но изначально грешил на код создания файла).
Так, что мое мнение — нету скуля, то решить можно с помощью и C++ (я бы на C# .NET писал-бы так как 10 лет разработки на нем, там вообще есть таблицы с поиском по хэшу котрые вообще все мега шустро все сделают. С++ под .NET тоже есть. Я знаю:)) и с помощью 1С (результат вполне рабочий). Есть скуль — задача решается гораздо проще. Собственно мой пост и был про решение с помощью типовых механизмов которые тоже нужно знать и изучать, ибо скуль это не только хранилище плюс выборки. Там куча приблуд есть.
ЗЫ: Есть куча причин когда это плохой вариант. К примеру я использовал запуск exe файла для скачки, планировщик винды для регламента, и скуль как хранилище опять же с пакетами интеграции. Но! Все это может быть закрыто злобными админами и через файл + регламентное задание со скачиванием с помощью 1С может быть единственным решением.
(35)
Фактически доводкой можно считать обернутое в try-exception создание файла серий с «мусором». Т.е. три минуты моего времени (и то только благодаря лени).
Что тут у нас получается? На медленном серваке обычный код 1С вполне может потягаться с MS SQL, хотя, конечно, 5 секунд против полутора минут — это проигрыш в 18 раз. Но я не виноват, что 1С такая тупая корова. На том же питоне данный код будет работать со скоростью чтения файла, как и на С.
А по поводу хеш-таблиц (фактически тип map) — памяти тупо не хватит, т.к. номер сразу сыграет в вырожденный хеш и начнет кушать оную. Но попробовать можно. С другой стороны, а нафига козе баян — скорость чтения с диска полутора гигов даже на HDD не превышает 30 секунд.
Зато теперь ты знаешь, что «архитектура» — это не просто стены и крыша. И иногда можно сделать куда проще и без лишних телодвижений. Вот, например, развернуть у клиентов отдельную таблицу SQL — тот еще гемор, что просьба выделить на диске 10 гигов кажется шуточной.
За статью адназначна плюс, но долго это не будет работать.
(36)
перед этим нужно понять причину прежде чем оборачивать:)
Ну естесьно не все, а в рамках серии. Самый большой текстовик 5 мегов занимал по серии. Так, что хватит.
А вообще если мы будем говорить про оптимизацию, то можно первоначально создать файл где 1 бит это наличие паспорта. Серия + номер это 10 в 10й, это 1.2 гига. Это меньше чем текстовое хранение текущих паспортов. Если на сервере есть лишняя оперативка то вообще в нее можно загнать. Тогда проверка на наличие будет заключаться в чтении бита по заданному адресу. С этим можно играться и добиться хороших результатов. И это при том, что этот файл будет всегда фиксированного объема и точно не увеличится. К примеру, если на вход подавать отсортированный массив, то можно читать страницами в рамках серии, учитывая, что заведомо будет известен адрес начала и окончания информации по серии.
А кто спорил и где?:)
Я про это и написал в конце, что я против велосипедов, но иногда без них никуда.
(38)
Никаму нирасказывай )))
(23) не поделитесь, сколько стоила консультация?
Загрузка номеров паспортов в DBF файл.
1) Создание DBF файла без индекса в среде 1С.
2) Загрузка номеров программой на FoxPro.
3) Создание индекса в среде 1С.
Создание индекса быстро работает только в Win x64 на локальном диске. Т.к. требуется хорошее кэширование.
+(41)
Время выполнения 7 минут.
Файлы лежат локально в VM.
CPU: i7-8550U @ 1.80GHz (Turbo Boost выключен)
Реальная RAM: 16 GB
Хост: Ubuntu 16.04.6 LTS
Виртуальная машина: QEMU
Логиче