Vollständige Version anzeigen : import csv große mengen


onip
15.10.2014, 11:06

tag zusammen,

ist ein paar tage her das ich mich wieder hier melde.
hoffe euch geht's gut.

hab ein problem das ich einfach nicht gelöst bekomme.
ich muss mehrere csv datein für ein shop importieren.
csv können zb. hersteller, kategorien, artikel usw. sein.
soweit läuft alles wie es soll.
ich öffne die datei verarbeite sie und übergebe ein array
mit datensätzen an eine schleife, die:
1. datensatz für die tabelle aufbereiten
2. guckt ob der datensatz schon da ist
3. wenn da update, sonst insert

was soll ich sagen artikel z;b. hat +18000 datensätze :(
genau, mir fliegt der mist um die ohren.

hab nun folgendes versucht:
array per chunk in 100er blöcke teilen und 100er datensätze an die schleife.
naja zumindest ist er jetzt von 4000 auf 9000 einträge gekommen.
ist also auch noch nicht das gelbe vom ei.

bin auf folgendes gestoßen:
Bei sowas ist es oft sinnvoll die Datei nur Stückchenweise einzulesen, dann das Stück verarbeiten, aus dem Speicher werfen und danach das nächste Stück einzulesen. Dann brauchst du auch nicht mehr vo viel Ram, also eigentlich so gut wie gar keinen mehr;

ok die datei nur 100 zeilen auszulesen und diesen datensatz zu übergeben raff ich.
aber was ist mit aus dem 'speicher werfen' gemeint?

gibt es ggf ein workaround für solche fälle wie meins?

Hardware Preisvergleich | Amazon Blitzangebote!

Videos zum Thema
Video Loading...
June
15.10.2014, 11:11

wieso schreibst du nicht erst alles in eine mysql db und verarbeitest es dann?


onip
15.10.2014, 11:15

was ist da der unterschied?
ob meine infos von ner csv oder von der DB kommen.
nur das ich ein schritt mehr habe.
eine schleife von 18000 ist 18000, die halt verarbeiten, prüfen, insert/update muss.

versteh ich da was falsch?


raid-rush
15.10.2014, 13:12

Dein Problem ist, das du mit PHP: str_getcsv - Manual (;php~net/manual/de/function;str-getcsv;php) die ganze CSV in ein Array lädst was unter umständen einen Fehler gibt wenn die php memory limits überschritten werden.

Das kannst du beheben, in dem du den zweiten Parameter angibst und immer zb 1000 Zeilen verarbeitest:

$handle = fopen ("test;csv","r");
while ($data = fgetcsv($handle, 1000, ';'))
{
foreach($data AS $line){
// $line[id] etc verarbeiten.
}
}


June
15.10.2014, 13:16

du kannst 10 mal mitm auto um nen käsetörtchen fahren oder 10 mal um den eifelturm
eins von beiden dauert sicher länger.

Ich habe mal ein ähnliches Szenario gehabt, probiers erstmal aus, sollte ja fix gehen.


onip
15.10.2014, 14:35

;raid
fgetcsv($handle, 1000, ...

der zweite parameter gibt mir nicht an wieviel zeilen er auslesen soll.
Gibt eine Zeile bis zu length -1 Bytes Länge zurück, welche aus der Datei von der aktuellen Position des Dateizeigers handle aus ausgelesen wird. Die Zeile endet an einem Zeilenumbruch (welcher im Rückgabewert enthalten ist), EOF (Ende der Datei) oder bei length - 1 Bytes (je nachdem, was eher auftritt). Ist keine Länge angegeben, wird diese auf 1k bzw. 1024 Bytes gesetzt;
ich versteh das so, dass er anzahl der zeichen in einer zeile oder bis ende der zeile zurückgibt.

;june
hast recht. den ansatz verfolge ich mal.
hab jetzt die artikel in ne tmp tabelle gepusht. dauer 30 sek. bei 15133 datensätzen.
der vorteil daran ist, dass ich bei artikel auch categories, varianten, similar, crosselling, images habe.
das läßt sich über ne DB deutlich besser herausfiltern als über ein *;csv.

ich werde das mal weiter spinnen und berichten.


Murdoc
15.10.2014, 15:29

Anderer Ansatz:
1000 Datensätze verarbeiten, Seite neu laden (frischer Prozess/Thread) und weiter machen wo man aufgehört hat.

$seek = isset ($_GET['seek']) ? $_GET['seek']|0 : 0;
$done = false;
$fp = fopen('datei;csv', 'r');
if (!$fp) exit('datei nicht lesbar');
fseek($fp, $seek, SEEK_SET);

for ($i = 0; $i < 1000; ++$i) {
$csv = fgetcsv($fp); // length auf 0 lassen

verarbeite_csv($csv);

if (feof($fp)) {
$done = true;
break;
}
}

$seek = ftell($fp);
fclose($fp);

if (!$done) {
reload_oder_neuer_prozess($seek);
exit;
}

echo 'fertig!';


Üver CLI wäre fork oder `php program;php --seek=..;` ne Möglichkeit.


onip
15.10.2014, 15:39

danke murdoc, das werde ich auch mal antesten.
hat nur einen nachteil bei artikel (nur da), ich muss similar und crosselling
aufzeichnen um nachträglich mit artikel update diese hinzu fügen zu können.

bei artikel die noch nicht in der DB stehen, fliegt mir similar und crosselling um die ohren :(

// edit
kann ich doch verwenden. und läuft super.
ich mach einfach ein verweis auf sich selbst, statt eines reload.

public function readFile($seek=0, $row=1) {
$done = false;
$fp = fopen($this->csvFile, 'r');
fseek($fp, $seek);
for ($i = 0; $i < 100; ++$i) {
$line = fgets($fp);
$seek += strlen($line);
$data = str_getcsv(trim($line), ";", '"');
if (feof($fp)) {
$done = true;
break;
}
if($row > 1){
$this->insert($data);
}
$row ++;
}
fclose($fp);
if (!$done) {
$this->readFile($seek, $row);
}else {
$this->run();
}
}

musst nur feof() vor verarbeitung ausführen, damit keine fehlere auftreten.
jetzt muss ich mal das mit ner datei versuchen die 196628 datensätze hat :)


onip
17.10.2014, 13:42

so,

stand der dinge eigentlich sehr gut. bis auf die blöden 500ter server error.

ich führe mit 'php import;php' das script aus.

1. anfrage per curl welche imports zu tun sind.
(z;b. supplier;csv, category;csv, property;csv, article;csv)

2. schleife mit curl um per seek (/property/seek/24223) eigene DB zu befüllen ala June.
sehe doch einige vorteile erstmal alles in die DB festzuhalten um dann das richtige import auszuführen. gerade für article perfekt.

supplier und category rattern durch und sind fix eingetragen.
property und article machen mir zu schaffen.
gerade propertys mit 200000 einträgen.
nach ner zeit bekomme ich eben 500ter error.
hab das gefühl das die andere seite sich verhaspelt mit den vielen crul anfragen.

teste gerade mit sleep(3) das mal zu verlangsamen.

public function exeCute ($link, $seek='') {
$result = $this->call($link;$seek);
if($result->data->seek != 'done'){
echo $link;'/seek/';$result->data->seek;"\r\n";
sleep(3);
$this->exeCute($link, '/seek/';$result->data->seek);
}
return true;
}


naja 3 sek. schlaf bei 200000 einträgen macht zu viel zeit mit nix tun :(
aber bis jetzt kommen keine abbrüche.

daher nun zum neuen problem.
was kann ich tun das zu beschleunigen ohne sleep und den 500ter error?

ich hab jetzt schon 4 versionen mit unterschiedlichen ansätzen.
einige haben den memory belastet (behoben) aber der 500ter error macht mir zu schaffe :(

// edit
das script läuft nun schon seit 1,5 std. ohne abbrüche.
es wurden bisher alle supplier, category und 153k propertys eingetragen.


Murdoc
17.10.2014, 14:55

Das läuft seit 1;5 std? Kann ich mir nicht vorstellen ...
Du nutzt da nen rekursiven Aufruf der dir zwangsweise nen stack-overflow erzeugen wird :D

Deswegen habe ich meine Funktion auch "reload_oder_neuer_prozess" genannt.


onip
17.10.2014, 15:01

ne, läuft.
liegt wohl am max_time_out.
der macht schön brav seine sache.
aber halt langsam.


Murdoc
17.10.2014, 15:06

Bis dann

Fatal error: Allowed memory size of ... bytes exhausted (tried to allocate .... bytes) in ... on line ...

kommt.

Du wurdest gewarnt :D


onip
17.10.2014, 15:15

hehe, ne
503 Service Unavailable

es hätten nur noch 5k einträge gefehlt.
ich flipp noch aus :(

// edit
propertys (196136) sind drin, hurra.
dauer (property): 0 std. 29 min. 36 sek;
hab die einträge von 100 auf 400 erhöht.


Ähnliche Themen zu import csv große mengen
  • Aufgabe mit Mengen und Abbildungen
    Grüße an die Gemeinde, ich muss mich gerade mit Mengen und Abbildungen beschäftigen und bin dabei auf eine Aufgabe gestoßen, die mich sehr interessiert, mir aber großes Kopfzerbrechen bereitet: gegeben seien eine Abbildung f:M -> N und Teilmengen X1,X2 von M bzw. Y1,Y2 von N. Beweisen od [...]

  • Berechnen Sie die folgenden Mengen!
    Berechnen Sie die folgenden Mengen! (i) U Vereinigung [1/n ; 1] n € N (ii) Schnitt [-1/n ; 1/n) n € N Hinweis: Das archimedische Prinzip könnte helfen. Die Klammern sind natürlich extra - die eckigen für abgeschlossenes Intervall und die runden für offene Intervalle. Bei gu [...]

  • Delphi mengen Angaben
    Wie wär's mit der kompletten Aufgabenstellung? [...]

  • [PHP] große Mengen an Mails verschicken
    Hi, ich suche nach einer Möglichkeit viele Mails zu verschicken, für nen Newsletter oder Rundschreiben. Laut php~net ist die mail() funktion dafür ungeeignet weil die für jede E-Mail einen Socket öffnen und wieder schließen würde. Gibt es da schnellere Möglichkeiten? mfg Fuselmeister [...]



raid-rush.ws | Imprint & Contact pr