Zadejte hledaný výraz...

PHP – jak řešíte import dat

Filip T.
verified
rating uzivatele
(2 hodnocení)
11. 10. 2015 11:17:39
Zdravím,
rád bych se zeptal, jak řešíte import dat ( xml, csv ). Aktuálně mám jeden projekt kde pracuji s velkým množstvím "produktů" které potřebuji porovnat/upravit/smazat.
Vždy jsem to řešil tak že:
- načtu si z DB všechny produkty a uložim si je do pole ( několik polí: produkt, parametry, kategorie..)
- pomocí XMLReaderu postupně načítám XML feed a provádím potřebné úkony. ( a s tím průběžně promazavám pole )
Všechno fungovalo dobře, ale jen do doby kdy jsem zpracovával feed do cca 50k položek
( na serveru je k dispozici cca 1GB ramek )
Teď jsem ale narazil a dost tvrdě :D. Feed má přibližně 200k položek a v podstatě končím už při tahání dat z DB. ( V podstatě při vytváření polí to padá pro nedostatek RAM )
Dotaz tedy zní, jak to děláte Vy? Napadlo mě např. Data vytáhnout a uložit je někam do temp-souborů.. při procházení si pak vždy vytáhnout ze souboru jen potřebný data..
* Otázka zní, zda by nebylo rychlejší si ty data "po jednom" tahat z DB - na druhou stranu, to bude neuvěřitelné množství dotazů na DB.. ( tj. 200k vytažení + update + insert + delete )
Díky za všechny reakce ;)
11. 10. 2015 11:17:39
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145707
Jiří
verified
rating uzivatele
(1 hodnocení)
11. 10. 2015 11:36:32
A co brání tomu tahat ta data sekvenčně třeba po 10k nebo 50k, když to funguje a porovnávat vždy jen tu část?
11. 10. 2015 11:36:32
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145706
node
verified
rating uzivatele
(5 hodnocení)
11. 10. 2015 11:37:24
Ty si riadny blazon. Tahat 50k poloziek naraz. Pocul si uz o davkovom spracovani????
11. 10. 2015 11:37:24
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145705
Fido123
verified
rating uzivatele
(13 hodnocení)
11. 10. 2015 11:41:49
Řeším teď to samé. Správná úvaha jsou poslední dva řádky tvého příspěvku:
1. Projet soubor a všechny položky uložit do fronty do databáze. To je relativně nenáročná operace.
2. Postupně položky po jedné (případně v dávkách) vytáhnout z fronty, zpracovat a odstranit z fronty.
11. 10. 2015 11:41:49
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145704
Filip T.
verified
rating uzivatele
(2 hodnocení)
11. 10. 2015 11:44:57
Ne, opravdu nejsem blázen ;) ono když nevytahujete popisy a delší "texty", tak to jsou pole s hodnotama ( id, skladem 1/0, .. ) takže ono pole do 50k položek si vezme např. jen 50Mb ramek ( těch polí je samozřejmě více ), takže to opravdu není tak hrozný problém. ( Když mám k dipozici 1 GB ;) )
* V podstatě jsem ani nepočítal s tím, že by se mohl objevit feed s takovým množstvím.
Takže díky, asi opravdu zkusím sekvenčně načítat data po x-tísících.
11. 10. 2015 11:44:57
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145703
node
verified
rating uzivatele
(5 hodnocení)
11. 10. 2015 11:51:26
Ono ide o to ze ked takto pises kod tak zle zmyslas uz v zaklade a to sa potom premieta aj dalej v programovani.
11. 10. 2015 11:51:26
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145702
It Snows In Hell
verified
rating uzivatele
11. 10. 2015 11:58:58
Mě na pár stovek tisíc položek v csv stačilo 5GB. Bylo jednodušší zvětšit kapacitu na vps (openvz) na 10 či 15 minut než rozdělit soubor na x souborů.
---------- Příspěvek doplněn 11.10.2015 v 11:00 ----------
Napsal node;1232301
Ono ide o to ze ked takto pises kod tak zle zmyslas uz v zaklade a to sa potom premieta aj dalej v programovani.
Co má společné psaní kódu s importem dat, kde je cca 200k položek?
11. 10. 2015 11:58:58
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145701
Filip T.
verified
rating uzivatele
(2 hodnocení)
11. 10. 2015 12:04:10
Díky i tobě Fido123, v podstatě to je logické :)
node: nejde o to, že "zle přemýšlím".. Ono pokud máš nějaké zadání, ve kterém je napsán "max." velikost zdroje a až po x-měsících zjistíš, že je 5x větší, než bylo v zadání, pak opravdu není problém ve mě - s tím souvisí i konfigurace serveru. ;)
Druhá věc na kterou bych se chtěl zeptat je, jak řešíte timeout webu? ( Cronem vím, ale teď mi jde spíše o "realtime" aktualizace uživatelem )
* Když nemáte přistup k rootu samozřejmě - budeme se teď bavit o "normálním" hostingu ( kde v podstatě nemůžete nic :D )
napadlo mě:
- zjistit timeout webu
- x-sekund před koncem típnout XML read, uložit pozici a přes JS udělat redirect
- pokračovat dále
Ale nevím jestli to není "hovadina" a šlo by to řešit lepší cestou
11. 10. 2015 12:04:10
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145700
Petr Holomoj
verified
rating uzivatele
(22 hodnocení)
11. 10. 2015 12:20:16
Také data importuji dávkou. Pro "normální hosting" (60s) se mi to osvědčilo. Importuji a aktualizuji asi 12k produktů z XML ( 15MB )
Před importem se stáhne soubor na FTP, aby se rychleji načítal.
Import následně kontroluje a zpracovává data.
Před samotným importem data zpracovává několik funkcí na úpravu dat( změna odkazů v textu, změna názvu, generování seo, atd.)
Samotný import obsahuje:
- IMPORT PRODUKTU (texty,kód, ceny, přidání asociací, atd...)
- IMPORT KATEGORIÍ
- IMPORT ATRIBUTU
- KOPÍROVÁNÍ OBRÁZKU (pro jeden záznam v průměru 3)
Dávka se určuje podle aktuálního záznamu z XML ( společně ze záznamem v DB). Neukončuji import v půlce ( nebo podle timeout ), ale vždy po dokončení dávky (po x produktech z XML) proto, aby byly vždy data k produktu kompletní.
11. 10. 2015 12:20:16
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145699
It Snows In Hell
verified
rating uzivatele
11. 10. 2015 12:26:10
Bohudík za root.
U některých hostingů stačí dát
ini_set('max_execution_time', 60);
Většina z nich to však ignoruje, takže to buď udělám u sebe (pokud se jedná o jednorazovku) nebo dávky / zaznamenání posledního ID.
11. 10. 2015 12:26:10
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145698
Smazany ucet 253
verified
rating uzivatele
(3 hodnocení)
21. 11. 2015 00:33:58
Pokud parsuješ obrovské XML, pak vyzkoušej XMLReader v kombinaci s DOMDocument, například takto:
$xml = new XMLReader;
$xml->open('/some/file.xml');
$dom = new DOMDocument;
// tímto jednoduše přeskočíš na požadovaný název tagu, od kterého chceš začít ...
while ($xml->read() && $xml->name !== 'SomeTagName');
while ($xml->name === 'SomeTagName') {
// importuješ pouze jeden uzel, nikoli celý soubor
$node = simplexml_import_dom($dom->importNode($xml->expand(), true));
$product = (string) $node->PRODUCT;
$id = (string) $node->ID;
$xml->next('SomeTagName'); // přeskočíš na další uzel
}
Chce to trošku si s tím pohrát ... jinak doporučuji INSERT pomocí SQL typu:
lze díky tomu vložit např. 1000 záznamů najednou a zabere to pro InnoDB opravdu krátký čas oproti vkládání po jednom ... samozřejmě hromadný update lze pouze u položek, kterým lze hromadně updatovat stejné hodnoty ... např.
21. 11. 2015 00:33:58
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145697
Filip T.
verified
rating uzivatele
(2 hodnocení)
22. 11. 2015 08:16:10
Díky rapemer, používám v podstatě naprosto stejný postup, s tím rozdílem, že vnitřní řetězec načítám jednoduše přes:
Samotné zpracování XML mi probíhá bez problémů a zpracuji bez problémů XML importy ve velikosti kolem 500 MB:
- zjistím si timeout
- nastavím si rezervní čas na zpracování zbytku skriptu ( timeout - 2s )
- procházím XML a kontroluji s rezervním časem
- pokud sem u konce ( timeout -2 ), uložím si do "Session" počet zpracovaných uzlů, zpracuju zbytek skriptu a udělám přes JS redirect
- skript prochází XML od znovu, s tím, že "přeskočím" X-zpracovaných uzlů. ( resp. simplexml_load_string se použije až od x-tého produktu )
Teď ale řeším jiný problém a to s DB.. i když si dám rezervních 5s ( timeout - 5s ), tak se často stává, že DB provádí nějaký insert i 10 - 15s ( nestíhá inserty/updaty? nevím ) a skript stejně spadne.
* Proběhne dejme tomu 6500 insertů a zničeho nic následný insert ( 100 položek ) trvá 10s..
Je možné nějakým způsobem přerušit aktuální "transakci" abych mohl udělat redirect a skript nespadl? ( tzn. aktuální transakce insertů/updatů se provede znova )
Díky
22. 11. 2015 08:16:10
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145696
Smazany ucet 253
verified
rating uzivatele
(3 hodnocení)
22. 11. 2015 18:44:45
Já jsem zvyklý na VPS nebo dedikované servery, takže time limit řešit nemusím.
Pokud máš možnost spouštět cokoli přes CLI nebo pomocí funkce exec(); tak celou synchronizaci spusť jako proces na pozadí přes konzoli CLI... Velmi vhodný pomocník je Symfony Console Component
1. krok - instalace přes Composer
2. krok - hlavní spustitelný soubor console.php
#!/usr/bin/env php
require __DIR__.'/vendor/autoload.php';
require __DIR__.'SyncCommand.php';
use SymfonyComponentConsoleApplication;
$application = new Application();
$application->add(new SyncCommand());
$application->run();
3. krok - samostatný command v souboru SyncCommand.php
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
class SyncCommand extends Command
{
/** @var PDO $connection */
protected $connection;
protected function configure()
{
set_time_limit(0);
$this->setName('run:sync');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// připojení do databáze..
$this->connect();
// Tvoje logika synchronizace
// pokud nejsi zvyklý na objektový model, tak to 'všechno naflákej sem' :-)))
}
protected function connect($engine = 'mysql', $host = 'localhost', $database = 'custom_db', $user = 'root', $pass = '')
{
$dsn = "{$engine}:dbname={$database};host={$host}";
$this->connection = new PDO($dsn, $user, $pass);
}
}
4. krok - spuštění
- předpokládám, že hosting běží na Linuxovém stroji a předpokládám, že máš možnost použít funkci exec();
$command = 'php /absolutni/cesta/k/souboru/console.php run:sync >/dev/null 2>&1 &';
exec($command);
// tímto se spustí process na pozadí a tento script se ukončí, takže nečeká na jeho dokončení
// chceš-li proces killnout, tak takto:
exec('kill -SIGKILL ' . system("ps aux | grep run:sync | grep -v grep | awk '{print $2}' "));
---------- Příspěvek doplněn 22.11.2015 v 18:57 ----------
Jinak rozumné řešení je ukládat si do Session po každé iteraci poslední položku, která byla uložena do databáze. V případě překročení timelimit začneš znovu tam, kde si zkončil :-)
22. 11. 2015 18:44:45
https://webtrh.cz/diskuse/php-jak-resite-import-dat#reply1145695
Pro odpověď se přihlašte.
Přihlásit