Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][AJAX] Import danych z dużego pliku XML
Forum PHP.pl > Forum > PHP
duch4ever
Witam, mam spory plik z hurtowni (prawie 40MB) i chcę go zaimportować przez PHP do bazy danych. Napisałem sobie skrypt który przez ajax stopniowo dodaje/aktulizuje dane ($xml->read()) jednak nie jest to dość optymalne i działa kilka godzin (skrypt otwiera plik, zczytuje część danych i zamyka). Można to zrobić jakoś lepiej? Może jest jakiś sposób o którym nie wiem?

Pliku oczywiśćie nie moge zczytać w całości gdyż skrypt musi działać na wirtualnym serwerze przy 128MB pamięci dla PHP. Bardzo proszę o pomoc.
Pozdrawiam
zegarek84
Cytat(duch4ever @ 26.11.2012, 15:09:46 ) *
Witam, mam spory plik z hurtowni (prawie 40MB) i chcę go zaimportować przez PHP do bazy danych. Napisałem sobie skrypt który przez ajax stopniowo dodaje/aktulizuje dane ($xml->read()) jednak nie jest to dość optymalne i działa kilka godzin (skrypt otwiera plik, zczytuje część danych i zamyka).

nie opisałeś jak to robisz, samo xml->read() nic nie mówi ;p
Cytat(duch4ever @ 26.11.2012, 15:09:46 ) *
Można to zrobić jakoś lepiej? Może jest jakiś sposób o którym nie wiem?

Pliku oczywiśćie nie moge zczytać w całości gdyż skrypt musi działać na wirtualnym serwerze przy 128MB pamięci dla PHP.

Jasne, że można i można to zrobić przy mniej dostępnej pamięci ;p

do google hasło "SAX PHP" - będziesz miał też odwołanie do manual'a PHP "XML Parser", jednak poczytaj sobie toutoriale jak z tego korzystać... całość będziesz musiał napisać zdarzeniowo w PHP podpinając callbacka pod parsera, oczywiście Tobie będzie potrzebna bardziej skomplikowana obsługa dynamicznych zdarzeń niż w przykładach, które znajdziesz w google...

w tym parserze będziesz miał info, do jakiego tagu wchodzisz, poziom zagłębienia itd... w PHP zdarzeniowo funkcje czy metody klas możesz wywoływać np. w ten sposób $this->{'moja_metoda'}($argument) oraz poczytaj o callbackach w PHP http://www.php.net/manual/en/language.types.callable.php

dodatkowo możesz w bazie przechowywać jakiś unikalny zewnętrzny harakterystyczny klucz... dodając do bazy nie dodaj do tej tabeli tylko do tymczasowej o tej samej strukturze w transakcji rekord po rekordzie (i nie zapamiętuj tych miennych), po dodaniu wszystkich rekordów do tabeli tymczasowej wykonaj zapytanie (inserta) dodające rekordy z tabeli tymczasowej do tabeli docelowej po kluczach unikalnych zewnętrznych (harakterystycznych) których nie ma w tabeli docelowej (chyba to się nazywa iloraz na danych bazy - ale to tylko ciekawostka nazewnictwa ;p), czyli INSERT SELECT hasło...

o dodawaniu wartości do tabeli tymczasowej wspomniałem dlatego, iż ja nie byłem pewnych danych które będą dopisywane do bazy czy czasem się nie powtórzą - pewne statystyki robiłem na bazie zewnętrznych danych XML jakieś 1,5 roku temu... a ponieważ dane nie są sprawdzane po stronie klienta czy istnieją w bazie a dopiero przez samą bazę to to działa dosyć szybko...
duch4ever
Dzięki kolego, troszkę poczytałem i testuję. Mój dotychczasowy skrypt działa mniejwięcej tak:

  1. $xml = new XMLReader();
  2. if(!$xml->open('XML.xml'))
  3. return false;
  4.  
  5. while($xml->read())
  6. {
  7. if($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'produkt')
  8. {
  9. // kod
  10. }
  11. }


Możesz wyjaśnić czym metoda podana przez ciebie różnie się od tej? Z tego co wstępnie zauwazyłem moja metoda nie pobiera pamięci bo nie ładuje pliku do ramu natomiast podana przez ciebie na start zabiera 40MB. Sprawdzałem wypisanie pozycji z XMLa (niecałe 20 000 pozycji, zwykłe echo). Szybkościowo działają dość podobnie, może o czymś nie wiem więc pytam.

Wydaje mi się że dzięki temu mam lepsze poruszanie po pliku XML tak?
Dizęki wielkie za zainteresowanie.
zegarek84
Cytat(duch4ever @ 26.11.2012, 17:46:15 ) *
Możesz wyjaśnić czym metoda podana przez ciebie różnie się od tej? Z tego co wstępnie zauwazyłem moja metoda nie pobiera pamięci bo nie ładuje pliku do ramu natomiast podana przez ciebie na start zabiera 40MB. Sprawdzałem wypisanie pozycji z XMLa (niecałe 20 000 pozycji, zwykłe echo). Szybkościowo działają dość podobnie, może o czymś nie wiem więc pytam.

Wydaje mi się że dzięki temu mam lepsze poruszanie po pliku XML tak?

jeśli nie masz skomplikowanej struktury XML'a to w sumie nie musisz podpinać listenera... ale pamięci nie powinno Ci więcej zużywać przy listenerze (boć może podpinasz go kilka razy i/lub tworzysz wiele obiektów listenerów i w efekcie masz wyciek pamięci), ja opisałem ogólnie to jak ja zrobiłem a plik był dosyć rozbudowany i nieźle pozagniezdrzany, więc musiałem wiedzieć, gdzie w danym momencie jestem, który raz dany tag jest otwierany i na jakim zagłębieniu... nie podawałem żadnej metody ;]

możesz wrzucić w sumie tamten kod co Ci zjada pamięć...
duch4ever
O wycieku raczej nie mam mowy to wręcz tutorialowy skrypt z jedną pętlą wypisującą kolejne tagi. Przypuszczam że tak to ma działać że pobiera do pamięci cały plik, pobierało dokładnie 40MB czyli tyle ile waży XML.

Nie ważne, zapewne niezależnie z jakiej metody skorzystam czas dostępu będzie podobny. Chyba muszę pomyśleć o cachowaniu, może dobrym pomysłem będzie najpierw zapisanie całego pliku do bazy a następnie odczyt już z bazy po 10 wierszy niż otwierać plik i pobierać z pliku 10 pozycji? Dodam że skrypt wymaga też pobrania zdjęć z linków w pliku xml więc po więcej niż 10 się nie da.
zegarek84
Cytat(duch4ever @ 26.11.2012, 23:32:16 ) *
Przypuszczam że tak to ma działać że pobiera do pamięci cały plik, pobierało dokładnie 40MB czyli tyle ile waży XML.

Pobiera dokładnie tyle ile chcesz by pobrało... no luknij dobrze chociaż na przykład z manuala:
http://www.php.net/manual/en/example.xml-structure.php
a dodatkowo na parametry funkcji xml_parse, a jeśli dane pobrałeś przez file_get_contents to już tylko Twoja sprawa ;]

luknij jeszcze na temat:
[PHP]parsowanie pliku txt, Jak odczytać wybrany zakres linii z pliku txt, choć nie programuję zawodowo to wiem o co chodzi...
darko
40 MB to jeszcze nie jest jakiś mega zbiór, jeżeli masz możliwość wykonania load data infile w mysql, to polecam przekonwertować xml do formatu csv, a później już pójdzie z górki.
duch4ever
Sprawdziłem i w tym przypadku odczyt jest szybszy starym sposobem (1.2s kontra 1.8s), co do pamięci żeczywiście z rozępdu załadowałem cały plik.

Czy SplFileObject będzie działać dobrze z plikami XML? Z tego co wyczytałem jest to świetne ale do plików CSV i czytania linii z pliku.
40MB to nie dużo ale operacji jest później sporo, pobieranie grafik itp.
zegarek84
Cytat(duch4ever @ 27.11.2012, 20:26:32 ) *
Czy SplFileObject będzie działać dobrze z plikami XML? Z tego co wyczytałem jest to świetne ale do plików CSV i czytania linii z pliku.

przecież jeśli z niego nie chcesz korzystać to masz strukturalne odpowiedniki metod tej klasy jak fopen itd... tamta klasa służy tylko do odczytu/zapisu pliku, sam XML musisz inaczej odczytywać... tzn w większości przypadków funkcje współpracują i jeśli wiesz, od której linii chcesz kontynuować to możesz do niej przewinąć od razu...

a co do szybkości to na prawdę wszystko zależy od tego jak to masz zrobione...
cudny
Ehh... tak na prawdę można się spierać nad szybkością, wydajnością i w ogóle.
Tak na prawdę trzeba sobie zadać podstawowe pytanie - po co Ci to jest ?
Bo jeśli jest to z hurtowni i masz taki plik powiedzmy raz na dobę i tylko zbierasz dane u siebie na serwerze w jakiś niecnych celach to puki co nie ruszaj tego i tyle.
Jeśli jednak będziesz tymi danymi obracał całą dobę i potem uzupełniał dane nowym plikiem xml to odpal sobie wszytko z cron'a i zaczytuj do bazy danych - serwer nawet tego nie poczuje jak zrobisz to w godzinach nocnych.
A obrazy zrzuć normalnie na dysk serwera i zaczytaj ścieżki do bazy.

Zanim pomyślisz jak te dane przetworzyć najwydajniej, zadaj sobie pytanie jak je będziesz wykorzystywał.
duch4ever
Cytat
w większości przypadków funkcje współpracują i jeśli wiesz, od której linii chcesz kontynuować to możesz do niej przewinąć od razu

Nie rozumiem do końca, wiem że mogę przwinąć do lini ale w xml nie ma takiej struktóry jak csv (jedna linia to nie jedna "pozycja").

Cytat
Ehh... tak na prawdę można się spierać nad szybkością, wydajnością i w ogóle.
Tak na prawdę trzeba sobie zadać podstawowe pytanie - po co Ci to jest ?

Chodzi mi sam początek czyli odczyt danych z pliku, reszta jest gotowa.

CRONem nic nie zdziałam, dodanie jednej pozycji można sobie wyobrazić jak INSERT do 10 tabel i pobrani 10 zdjęć przez file_get_contents więc po 20 produktach jest time_limit w PHP i koniec (przypomnę że plik to prawie 20 000 pozycji). Dlatego musi być ajax do tego.

Ale już chyba mam najszybsze rowzianie, jeśli macie jeszcze jakieś sugestie proszę pisać.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.