Elasticsearch in Shopware nutzen

Ich habe in meinem ersten Beitrag darüber berichtet welche Vorteile Elasticsearch bietet und ab wann man es einsetzen sollte. Hier möchte ich kurz zeigen wie Ihr es einbindet und welche Stolpersteine Ihr beachten solltet.

Installation

Ihr solltet eine ES (Elasticsearch) Instanz in eurem internen Netzwerk zur Verfügung haben. Falls Ihr diese selbst einrichtet schaut euch diesen Beitrag an. Steht diese schon durch euren Hoster bereit braucht Ihr folgende Daten:

  • IP Adresse
  • Port (falls nicht 9200)

Erster Dump

Bevor Ihr das erste mal php bin/console sw:es:index:populate  ausführt solltet Ihr in s_es_backlog schauen. Hier befinden sich alle aktualisierten Daten, welche erst ab Version 5.2.13 zuverlässig bei einer inaktiven Config gespeichert werden (siehe Issuetracker)

Wenn Ihr noch nie ES genutzt habt, könnt Ihr die Table einfach mit

DELETE FROM `s_es_backlog` WHERE 1;

löschen.

Andernfalls kommt es zu unzähligen Error-Meldungen das Variantenpreise etc. nicht berechnet werden können.

Nun führen wir den populate Befehl aus:

php bin/console sw:es:index:populate --shopId=5

wir geben die entsprechende shopId mit um das ganze erstmal zu testen. Leider sehen wir in unserem Kibana Dashboard wieder nichts

Schauen wir uns doch mal die Error logs unter /var/log/elasticsearch/  an

[2018-03-25T17:54:11,554][DEBUG][o.e.a.b.TransportShardBulkAction] [MZZQtZz] [sw_shop5_20180325175220][3] failed to execute bulk item (index) BulkShardRequest [[sw_shop5_20180325175220][3]] containing [10] requests
java.lang.IllegalArgumentException: Limit of total fields [1000] in index [sw_shop5_20180325175220] has been exceeded
        at org.elasticsearch.index.mapper.MapperService.checkTotalFieldsLimit(MapperService.java:604) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.index.mapper.MapperService.internalMerge(MapperService.java:420) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.index.mapper.MapperService.internalMerge(MapperService.java:336) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.index.mapper.MapperService.merge(MapperService.java:268) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.metadata.MetaDataMappingService$PutMappingExecutor.applyRequest(MetaDataMappingService.java:311) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.metadata.MetaDataMappingService$PutMappingExecutor.execute(MetaDataMappingService.java:230) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.ClusterService.executeTasks(ClusterService.java:634) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.ClusterService.calculateTaskOutputs(ClusterService.java:612) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.ClusterService.runTasks(ClusterService.java:571) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.ClusterService$ClusterServiceTaskBatcher.run(ClusterService.java:263) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.TaskBatcher.runIfNotProcessed(TaskBatcher.java:150) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.cluster.service.TaskBatcher$BatchedTask.run(TaskBatcher.java:188) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:569) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:247) ~[elasticsearch-5.6.5.jar:5.6.5]
        at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:210) ~[elasticsearch-5.6.5.jar:5.6.5]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_151]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_151]

Das Limit der Felder von 1000 wurde überschritten – o.k. …

Hier fängt es dann in größeren Setups an tricky zu werden – in den meisten Fällen sind hier Plugins, Kundengruppen und andere Dinge Schuld. Der Index kann nicht angelegt werden, da ES im Standard „nur“ 1000 Felder erlaubt.

Hier muss man eine spezielle Lösung finden, auf die ich hier nicht eingehen möchte, da Sie den Rahmen sprengt (mehr dazu HIER)

Je nach Produktanzahl läuft das ganze innerhalb von 1-10 Minuten durch.

Maintaining des ES Index

Üblicherweise ändern sich Preise, Varianten etc. jeden Tag. Daher ist es wichtig die ES Daten immer auf dem aktuellsten Stand zu halten. Das ganze machen wir mir:

php bin/console sw:es:backlog:sync

Dieser nimmt die Daten die in der s_es_backlog Tabelle stehen und wendet Sie auf den bestehenden Index an.

Ihr solltet das ganze je nach Shop jede 15min bis 1  Stunde ausführen – am einfachsten geht das mit einem cronjob (crontab -e )

Beispielsweise über

* 0 * * * cd /var/www/shopware && /usr/bin/php bin/console sw:es:backlog:sync

Shopware empfiehlt einmal pro Tag einen Cronjob mit einer kompletten Reindexierung laufen zu lassen. Ich empfehle dies Nachts zu machen, da in dieser Zeit kein Traffic herrscht und der Prozess teilweise etwas dauert.

0 2 * * * cd /var/www/shopware && /usr/bin/php bin/console sw:es:index:populate

 

Fazit

In Kürze veröffentliche ich einen Artikel der sich mit dem Nutzen von ES beschäftigt. Dabei gehe ich darauf ein, ab wann sich ES wirklich lohnt. Grundsätzlich kann man davon ausgehen, dass man ES ab 30000 Artikel mit gutem Gewissen einsetzen kann. Darunter würde ich mit einem dedizierten DB Server nicht wirklich den Mehraufwand betreiben.

Wenn man einen Hoster hat der den ES Stack in vielen Setups betreibt, ist man auch auf der sicheren Seite. Komplex ist das ganze nicht wirklich, benötigt aber schon ein paar Vorkenntnisse.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert