Der Kommentar von vansiegmund hat mich dazu ermuntert, einen alten Posting-Entwurf hervorzukramen, und zwar die Antwort auf die Frage: wie kann ich mit PHP-Code einen Index neu aufbauen? Genauer gesagt wollte vansiegmund wissen, wie er mit einem PHP-Skript eine Re-Indizierung nach dem SOAP-Import veranlasst.
Ich nehme Magento 1.4.2.0 als Basis. In der neuen Version 1.5.0.1 habe ich noch nicht nachgesehen, aber vermutlich ist der Ablauf dort ähnlich.
Neu-Indizierung per Shell-Skript
Wenn ihr die Indizes über ein Bash-Skript aktualisieren wollt, könnt ihr auf die Datei shell/indexer.php zurückgreifen.
Der Aufruf ohne Parameter liefert Informationen zur Verwendung des Skripts:
# wenn wir uns im Verzeichnis shell/ befinden: /usr/bin/php -f indexer.php Usage: php -f indexer.php -- [options] --status Show Indexer(s) Status --mode Show Indexer(s) Index Mode --mode-realtime Set index mode type "Update on Save" --mode-manual Set index mode type "Manual Update" --reindex Reindex Data info Show allowed indexers reindexall Reindex Data by all indexers help This help Comma separated indexer codes or value "all" for all indexers
Wenn wir alle Indizes neu aufbauen wollen, reicht uns somit folgender Befehl:
php -f indexer.php reindexall
Oft ist das aber gar nicht nötig, da von Updates nur einzelne Indizes betroffen sind.
Sehen wir uns an, welche Indizes zur Verfügung stehen:
php -f indexer.php info catalog_product_attribute Product Attributes catalog_product_price Product Prices catalog_url Catalog URL Rewrites catalog_product_flat Product Flat Data catalog_category_flat Category Flat Data catalog_category_product Category Products catalogsearch_fulltext Catalog Search Index tag_summary Tag Aggregation Data cataloginventory_stock Stock Status
Wir können uns nun näher informieren, ob der Index automatisch oder manuell aktualisiert wird und ob eine Neuberechnung gerade nötig ist:
php indexer.php --mode catalog_product_attributes Product Attributes: Update on Save
php indexer.php --status catalog_product_attribute Product Attributes: Pending
Weitere Index-Status sind
- Require Index (muss neu indiziert werden),
- Running (Indizierung läuft momentan) und
- Ready (Index ist aktuell).
Entschließen wir uns nun dazu, einen Index zu erneuern, dann sieht das so aus:
php indexer.php --reindex catalog_product_attribute Product Attributes index was rebuilt successfully
Diese Meldung erscheint für jeden einzelnen Index. Falls die Indizierung misslingt, wird eine entsprechende Fehlermeldung oder – falls keine vorhanden ist – die Meldung
[Name des Index] index process unknown error
ausgeworfen.
Indizierungsmodus ändern
In manchen Situationen ist es sinnvoll, die automatische Indizierung vorübergehend zu deaktivieren. Zum Beispiel haben meine Tests zur Performance des SOAP-Imports ergeben, dass die Umstellung auf manuelle Indizierung ein Viertel der Zeit einspart.
In der Shell kann man dank indexer.php den Modus für einzelne oder alle Indizes ändern:
php indexer.php --mode-manual all Product Attributes index was successfully changed index mode Product Prices index was successfully changed index mode Catalog URL Rewrites index was successfully changed index mode Product Flat Data index was successfully changed index mode Category Flat Data index was successfully changed index mode Category Products index was successfully changed index mode Catalog Search Index index was successfully changed index mode Tag Aggregation Data index was successfully changed index mode Stock Status index was successfully changed index mode
php indexer.php --mode-realtime all Product Attributes index was successfully changed index mode Product Prices index was successfully changed index mode Catalog URL Rewrites index was successfully changed index mode Product Flat Data index was successfully changed index mode Category Flat Data index was successfully changed index mode Category Products index was successfully changed index mode Catalog Search Index index was successfully changed index mode Tag Aggregation Data index was successfully changed index mode Stock Status index was successfully changed index mode
Neu-Indizierung per PHP-Skript
Um einen Index per PHP zu aktualisieren, benötigt man nichts weiter als die Datei app/Mage.php.
Mit dem folgenden Befehl werden der Index sowie alle von ihm abhängigen Indizes neu geschrieben. Alternativ kann man reindexAll() verwenden. Dann werden Abhängigkeiten nicht berücksichtigt.
require_once pfad/zu/app/Mage.php; Mage::app(); $process = Mage::getSingleton('index/indexer')->getProcessByCode('catalog_product_attribute'); $process->reindexEverything();
Wenn alle Indizes auf Vordermann gebracht werden sollen, holt man sich eine Prozess-Collection und ruft für jede einzelne reindexAll() auf. reindexEverything kann man sich in diesem Fall ersparen, da ohnehin jeder Index an die Reihe kommt.
$processCollection = Mage::getSingleton('index/indexer')->getProcessesCollection(); $processCollection->walk('reindexAll');
Indizierungsmodus ändern
Natürlich kann man auch im PHP-Skript den Modus ändern, um beim Import Zeit zu sparen. Für den folgenden Code ergeht ein Dankeschön an Ivan Chepurnyi bei Stackflow:
$processes = Mage::getSingleton('index/indexer')->getProcessesCollection(); $processes->walk('setMode', array(Mage_Index_Model_Process::MODE_MANUAL)); $processes->walk('save'); // Here goes your // Importing process // ................ $processes->walk('reindexAll'); $processes->walk('setMode', array(Mage_Index_Model_Process::MODE_REAL_TIME)); $processes->walk('save');
Fazit
Nun steht hoffentlich nichts mehr im Weg, um Magentos Indizes auf dem aktuellen Stand zu halten!
Hey Matthias,
danke für den Beitrag.
Ich habe momentan in einem Shop (1.7) ein Phänomen, welches ich mir nicht erklären kann. Vielleicht hast du mir einen Quick-Tipp?
Ich indexiere – je nach Bedarf – über einen nächtlichen Cronjob, welcher die Indexe direkt aktuallisiert oder auch über die Shell. Jeweils wird immer nur ein einzelner Index aktuallisiert. (Also nicht über reindexall).
Ab und an wurde z.B. das Fertigstellungs-Datum des Attribut-Index nicht mehr aktuallisiert und auch das Backend-Feld „Update erforderlich“ blieb immer auf rot. (lt. Shell-Ausgabe keinerlei Fehler).
Nach dem leeren der index_event und index_process_event Tabellen lief es dann wieder tadellos. Für ein paar Tage.
Nun bringt jedoch selbst das leeren dieser Tabellen nichts mehr. Der Index wird zwar geupdated, jedoch nicht das Datum sowie der Flag „Update erforderlich“. Auch der Status wechselt direkt nach dem Ausführen von „Verarbeiten“ wieder zu „Neuaufbau nötig“. Somit startet der nächtliche Index-Update immer wieder beim Attribut-Index und führt die restlichen nicht aus.
Zur Info: Alle Indexes (bis auf Lagerbestand), stehen auf „Manuelles Update“. All diese Indexe betrifft das selbe Problem.
Ich hoffe, du kannst mir hier weiterhelfen!
Liebe Grüße aus Kempten und schonmal ein „Danksche“.
Ich würde als Erstes sicherstellen dass der PHP-Prozess ein ausreichend hohes Memory-Limit hat – wohlgemerkt auch in der PHP-Konfiguration für die Shell. Dann würde ich die diversen Magento-Logs und den PHP-Error-Log beobachten. Normalerweise spucken fehlerhafte Indizierungsprozesse eine Meldung aus.
Hi Matthias,
vielen Dank für deinen Blog 🙂
wenn ich über die shell catalog_product_price reindexen will bekomme ich folgende Fehlermeldung:
/html/mage-672c1fbd/shell$ php indexer.php –reindex catalog_product_price
Product Prices index process unknown error:
exception ‚PDOException‘ with message ‚SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count
doesn’t match value count at row 1‘ in /html/mage-672c1fbd/lib/Zend/Db/Statement/Pdo.php:228
Stack trace:
#0 /html/mage-672c1fbd/lib/Zend/Db/Statement/Pdo.php(228): PDOStatement->execute(Array)
#1 /html/mage-672c1fbd/lib/Varien/Db/Statement/Pdo/Mysql.php(110): Zend_Db_Statement_Pdo->_execute(Array)
#2 /html/mage-672c1fbd/app/code/core/Zend/Db/Statement.php(291): Varien_Db_Statement_Pdo_Mysql->_execute(Array)
#3 /html/mage-672c1fbd/lib/Zend/Db/Adapter/Abstract.php(479): Zend_Db_Statement->execute(Array)
#4 /html/mage-672c1fbd/lib/Zend/Db/Adapter/Pdo/Abstract.php(238): Zend_Db_Adapter_Abstract->query(‚INSERT INTO `ca…‘,
Array)
#5 /html/mage-672c1fbd/lib/Varien/Db/Adapter/Pdo/Mysql.php(428): Zend_Db_Adapter_Pdo_Abstract->query(‚INSERT INTO `ca..
.‘, Array)
#6 /html/mage-672c1fbd/app/code/community/OrganicInternet/SimpleConfigurableProducts/Catalog/Model/Resource/Eav/Mysql4/
Product/Indexer/Price/Configurable.php(133): Varien_Db_Adapter_Pdo_Mysql->query(‚INSERT INTO `ca…‘)
#7 /html/mage-672c1fbd/app/code/core/Mage/Catalog/Model/Resource/Product/Indexer/Price/Configurable.php(48): OrganicInt
ernet_SimpleConfigurableProducts_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Configurable->_prepareFinalPri
ceData()
#8 /html/mage-672c1fbd/app/code/core/Mage/Catalog/Model/Resource/Product/Indexer/Price.php(385): Mage_Catalog_Model_Res
ource_Product_Indexer_Price_Configurable->reindexAll()
#9 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Indexer/Abstract.php(143): Mage_Catalog_Model_Resource_Product_In
dexer_Price->reindexAll()
#10 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Process.php(210): Mage_Index_Model_Indexer_Abstract->reindexAll(
)
#11 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Process.php(258): Mage_Index_Model_Process->reindexAll()
#12 /html/mage-672c1fbd/shell/indexer.php(166): Mage_Index_Model_Process->reindexEverything()
#13 /html/mage-672c1fbd/shell/indexer.php(212): Mage_Shell_Compiler->run()
#14 {main}
Next exception ‚Zend_Db_Statement_Exception‘ with message ‚SQLSTATE[21S01]: Insert value list does not match column lis
t: 1136 Column count doesn’t match value count at row 1‘ in /html/mage-672c1fbd/lib/Zend/Db/Statement/Pdo.php:234
Stack trace:
#0 /html/mage-672c1fbd/lib/Varien/Db/Statement/Pdo/Mysql.php(110): Zend_Db_Statement_Pdo->_execute(Array)
#1 /html/mage-672c1fbd/app/code/core/Zend/Db/Statement.php(291): Varien_Db_Statement_Pdo_Mysql->_execute(Array)
#2 /html/mage-672c1fbd/lib/Zend/Db/Adapter/Abstract.php(479): Zend_Db_Statement->execute(Array)
#3 /html/mage-672c1fbd/lib/Zend/Db/Adapter/Pdo/Abstract.php(238): Zend_Db_Adapter_Abstract->query(‚INSERT INTO `ca…‘,
Array)
#4 /html/mage-672c1fbd/lib/Varien/Db/Adapter/Pdo/Mysql.php(428): Zend_Db_Adapter_Pdo_Abstract->query(‚INSERT INTO `ca..
.‘, Array)
#5 /html/mage-672c1fbd/app/code/community/OrganicInternet/SimpleConfigurableProducts/Catalog/Model/Resource/Eav/Mysql4/
Product/Indexer/Price/Configurable.php(133): Varien_Db_Adapter_Pdo_Mysql->query(‚INSERT INTO `ca…‘)
#6 /html/mage-672c1fbd/app/code/core/Mage/Catalog/Model/Resource/Product/Indexer/Price/Configurable.php(48): OrganicInt
ernet_SimpleConfigurableProducts_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Configurable->_prepareFinalPri
ceData()
#7 /html/mage-672c1fbd/app/code/core/Mage/Catalog/Model/Resource/Product/Indexer/Price.php(385): Mage_Catalog_Model_Res
ource_Product_Indexer_Price_Configurable->reindexAll()
#8 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Indexer/Abstract.php(143): Mage_Catalog_Model_Resource_Product_In
dexer_Price->reindexAll()
#9 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Process.php(210): Mage_Index_Model_Indexer_Abstract->reindexAll()
#10 /html/mage-672c1fbd/app/code/core/Mage/Index/Model/Process.php(258): Mage_Index_Model_Process->reindexAll()
#11 /html/mage-672c1fbd/shell/indexer.php(166): Mage_Index_Model_Process->reindexEverything()
#12 /html/mage-672c1fbd/shell/indexer.php(212): Mage_Shell_Compiler->run()
#13 {main}
Hast evtl. einen Ansatz wie ich das beheben kann, da ich keine neuen Konfigurierbaren Artikel mehr in Kategorien verlinken kann?
Vielen lieben Dank!
Hallo, der Fehlermeldung nach mischt die Extension OrganicInternet_SimpleConfigurableProducts bei dem Code-Teil mit. Die Extension kenne ich nicht. Frage bei dem Hersteller nach, der wird am besten helfen können.
Hallo, vielen Dank für deine schnelle Antwort. Ich hab die Extension neu installiert und jetzt funktioniert wieder alles 🙂 Danke
Das ist alles perfekt beschrieben und sehr hilfreich, daher habe ich auch nur eine Kleinigkeit anzumerken:
Der Plural von „Status“ ist nicht „Stati“, sondern aufgrund der u-Deklination „Status“. 🙂
Viele Grüße,
Jan
Hallo Jan,
danke für den Hinweis – ist ausgebessert.
Danke für den Post. Schöne Zusammenfassung 🙂
Aktuell bauen sich die Indizes bei uns leider überhaupt nicht mehr auf.
Next exception ‚Zend_Db_Statement_Exception‘ with message ‚SQLSTATE[42000]: Syntax error or access violation: 1118 Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
CREATE TABLE `catalog_product_flat_14` (
Ebenso dauert das Attribute und Produkte speichern leider ewig.
Gibt es Shops, die die Indizies komplett auf manuell stellen und nur nachts per Cron aktualisieren?
Gruß Thorsten
Danke für das Lob! In dem Shop ist bei zu vielen Attributen die Einstellung „Used in Product Listing“ auf „Yes“ gesetzt. Dadurch stoßt ihr bei den Flat-Tables an eine Grenze von MySQL. Überprüft einmal, ob die Einstellung wirklich bei so vielen Attributen benötigt wird.
Ja, es gibt Shops, die das machen!
Ich habe auch ein Problme mit dem Index in Magento der ständig auf Verarbeitung stecken bleibt. Ich wollte diesen php Befehl probieren habe auch einen SSH Zugang zu Servplatz allerdings habe ich keine Ahnung wie ich den Befehl: php indexer.php –reindex absetzen soll?
Über FTP?
Welches Programm brauche ich da, ist der Symtax für den Befehl ok?
Kann ich auch ein Script auf dem Server in den Ordner Magento Ordenr shell ablegen, dass ich dann mit einem Browser aufrufe?
Sorry bin da etwas unbeholfen, da ich sowas noch nicht gemacht habe.
Ich finde zwar jede Menge Hinweise hierzu aber keine Hinweise wie man da GENAU vorgeht:
Danke für jede Hilfe
Nein, nicht über FTP, sondern über SSH. Mac OS bringt einen eigenen SSH-Client mit: https://kb.mediatemple.net/questions/1599/Using+SSH+in+Terminal.app+%28Mac+OS+X%29#gs
Der Befehl muss im Magento-Unterordner shell/ ausgeführt werden.
Wenn du noch gar keine Erfahrung mit der Shell hast, solltest du aber unbedingt die Basics lernen, bevor du dich damit auf ein Live-System wagst. Da kann man schnell etwas kaputt machen.
Wenn du das ein Script über den Browser abrufen willst, kannst du das gleich über das Magento-Backend machen.
Hi Matthias, 🙂
ist es ratsam ein Reindex in ein Setup-Script einzubauen? Oder spricht etwas dagegen (lange Laufzeiten z.B.)?
Grüße
Matthias
Hi Matthias ;),
in einem Live-System sehe ich die Gefahr, dass durch die längere Laufzeit mehrere Besucher das Upgrade-Script auslösen. Wenn die Site für alle anderen gesperrt wird, solange die Aktualisierung läuft, sollte es kein Problem sein. Am besten einfach einmal die Auswirkung in einem Staging-System testen.
Als Alternativen bleiben immer noch ein Cronjob, Shell-Script oder das Backend für die Neu-Indizierung.
Danke für die schnelle Antwort! Hat mir sehr geholfen. Ein Cron ist sicher eine gute Alternative!
Hallo Matthias,
ich habe mein Script nun komplett umgebaut und den Test auf der Shopversion 1.5.0.1 durchgefürt:
real 9m29.408s
user 6m9.103s
sys 0m57.852s
für 2650 Produkte, das ist doch super 10-12 Produkte pro Sekunde 😉
„walk(’setMode‘, array(Mage_Index_Model_Process::MODE_MANUAL));“
haben in meinem Script noch gefehlt.
Grüße
Fetten Dank auch an meiner Stelle an Ivan Chepurnyi von Stackflow!
Hallo,
das ist wirklich eine schöne Performance-Steigerung! 😉
Darf ich fragen, was du bei dem Test alles durchführst? (Kategorie-Zuordnungen, Bilder, Sprachen…)
lg Matthias
Guten Morgen,
derzeit erstelle ich nur die Produkte, bzw. überspiele die bestehenden um einen schnellen Stock und Price Update zu erzielen.
Um die ganze Sache komplett rund zu bekommen fehlt mir noch die On The Fly Produktgruppenerstellung, beim Artikelimport.
Leider komme ich nicht hinter wie die Magento Api zur Produktgruppenanlage intern aufgebaut ist. Habe schon das Netz durchforstet aber nur den Standard zur Produktanlage gefunden…
http://www.fontis.com.au/blog/magento/creating-magento-products-script
Hast du einen Tipp für mich? Das ist der Ansatz aus meinem Standard API Import.
if(!array_key_exists($s1, $c1)) {
$id_level1 = $category->setData(2, array(’name’=>$s1,
‚is_active’=>1,
‚include_in_menu’=>1,
‚available_sort_by’=>array(0),
‚default_sort_by’=>’Bewertung‘)
);
$c1[$s1] = $id_level1;