Magento-Indizes manuell neu erstellen

Ab und zu müssen Magento-Indizes aufgeräumt werden. (c) Horrgakx auf flickr.comDer 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!

19 Antworten

  1. Florian sagt:

    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.

  2. Robert Piper sagt:

    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.

      • Robert Piper sagt:

        Hallo, vielen Dank für deine schnelle Antwort. Ich hab die Extension neu installiert und jetzt funktioniert wieder alles 🙂 Danke

  3. JCG sagt:

    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.

    • Thorsten sagt:

      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!

  4. Giorgio sagt:

    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

  5. Matthias sagt:

    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.

  6. vansiegmund sagt:

    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

      • vansiegmund sagt:

        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;

  1. 24.02.2011

    […] This post was mentioned on Twitter by Matthias Zeis and LimeSoda, Bernd Pfeiffer. Bernd Pfeiffer said: RT @mzeis: How to update #magento indexes programmatically using PHP or shell http://ow.ly/42nIN (in German) […]

  2. 07.03.2011

    […] Zeis, bekannt durch seine guten umfangreichen Beiträge, hat sich einmal näher mit dem Indexer-Prozess beschäftigt. Ganz gut erklärt und noch mal ein wenig umfangreicher als unser eigener Beitrag zu […]