BigBridge Product Import voor Magento 2

Magento 2 is een enterprise e-commerce platform dat geschikt is voor honderdduizenden producten. De meegeleverde import tools kunnen deze hoeveelheden echter niet goed aan. Om dit op te lossen heb ik een import tool gemaakt voor de community.

English translation of this article.

De code

De code en documentatie staan hier

https://github.com/bigbridge-nl/product-import

Het bevat

  • een product import library voor maatwerk imports
  • imports voor XML (REST en file gebaseerd)
  • een tool om de the url_rewrite tabel te repareren

Introductie

In oktober 2017 worstelden we met enkele product imports. De eerste was een op REST gebaseerde sync die meerdere requests per product nodig had. Het kostte meerdere dagen om 40.000 products en 600 categorieën te importeren. De tweede was een sync van lokale XML files. Het was sneller, maar we moesten wel wat bochten afsnijden om het werkend te krijgen op een acceptabele snelheid. Ook hier was een complete update van alle producten bijna onwerkbaar.

Ik sprak hierover met Marco, mijn werkgever en collega, en we waren het er over eens dat het niet nodig zou moeten zijn dat product import zo veel tijd zou kosten. Uiteindelijk is het importeren van producten toch slechts een kwestie van het verplaatsen van data naar de database, niet waar? De low level processen van MySQL zijn snel genoeg. Wat als we de tussenpersoon, Magento, er uit konden halen door direct naar MySQL te schrijven? Dit zou moeten resulteren in een grote snelheidswinst. Een paar tests toonden aan dat dat klopte.

Ik wilde dit project doen voor de Magento community omdat het importeren van producten zo’n basis taak is dat het vrij toegankelijk voor iedereen zou moeten zijn. Daarnaast wilde ik me ook niet gehaast voelen en ik wilde de tijd nemen om het goed te doen. Het kostte me meer dan de drie maanden die ik ervoor ingeschat had, maar het project is dan ook veel uitgebreider geworden dan gepland.

Snelheid

Optimalisatie is leuk. Het geeft me een kick te zien hoe snel iets kan gaan. Dit zijn enkele technieken die ik hiervoor heb gebruikt:

In plaats van het één-voor-één importeren van producten, importeert de library producten in batches van 1000. Op deze manier is de overhead voor het verwerken van een product veel kleiner, en in sommige gevallen konden meerdere inserts zelfs in een statement worden uitgevoerd.

Het schrijven van records in een enkel statement is 2 tot 10 keer sneller dan het uitvoeren van afzonderlijke statements, dus ik wilde dit zo veel mogelijk gebruiken. MySQL heeft echter een maximum query size die gerespecteerd moet worden. Daarom vraag ik eerst aan de server de variable “max_allowed_packet” op om te weten hoe groot de query mag worden. Daarna pers ik zoveel mogelijk records in de INSERT als mogelijk. Omdat ik de library ook geen tijd wil laten verspillen met het opnieuw en opnieuw laten uitrekenen van de query grootte, geef ik een constante mee met elke query die aangeeft wat de maximale grootte is van een enkel record, met groottes van 1 KB, 2 KB, 16 KB of 128 KB. Bijvoorbeeld, als een record 2 KB inneemt en de max query size is 1 MB, kunnen er 500 inserts in een enkele query geplaatst worden.

Ik testte “met een klok in mijn hand”. Iedere keer dat ik een wijziging aan de code aanbracht, voerde ik een automatische benchmark uit met 2500 producten. Op deze manier had ik het meteen door als een wijziging aan de code invloed had op de snelheid. Zo ben ik op een aantal vertragende factoren gestuit waar ik anders niet op was gekomen en kon ik die anders aanpakken.

Ik mat ook het geheugengebruik om er voor te zorgen dat het op een laag niveau bleef en niet opliep bij grotere imports.

Nadat ik bedacht had dat het importeren van afbeeldingen wel eens een bottleneck zou kunnen worden maakte ik een file cache en een HTTP cache voor afbeeldingen. Op deze manier hoeven ze niet steeds opnieuw gedownload te worden.

Hoe snel is de library? Ik kan je niet vertellen hoe snel de library is in jouw situatie. Het hangt af van veel factoren. Het best kun je een kleine test maken om het zelf uit te vinden!

Nieuwe Features

Het implementeren van alle features die van een product import library verwacht mogen worden, was veeeeel werk. Maar daarnaast heb ik enkele nieuwe features toegevoegd die volgens mij ook nodig zijn.

Placeholders. Producten zijn op verschillende manieren verbonden met andere producten. Configurable-, groeps- en bundel-producten zijn verbonden met andere producten. Elk product kan gerelateerde, up-sell, en cross-sell producten hebben. Verbindingen tussen producten worden opgeslagen met hun id. Een product kan natuurlijk alleen worden opgeslagen als de producten waarmee het verbonden is al bestaan. Producten kunnen zelfs naar elkaar terug verwijzen. Dit probleem wordt vaak over het hoofd gezien.

Ik heb deze situatie aangepakt door placeholder (plaatsvervanger) producten te maken voor producten waarnaar verwezen wordt, maar die nog niet bestaan. Een dummy placeholder product wordt hiervoor aangemaakt, voornamelijk voor zijn id. Als het eigenlijke product dan wordt geïmporteerd, wordt de placeholder vervangen door het echte object.

Url key generatie. Url keys zijn uniek per store view. Ze worden gewoonlijk gegenereerd gebaseerd op de naam van het product, en meerdere producten hebben vaak dezelfde naam. Omdat dit een probleem blijkt te zijn sta ik de gebruiker toe om de url key te genereren op basis van de naam of de sku. Als deze url key conflicteert met een andere, kun je kiezen wat je eraan wilt doen: de sku toevoegen, of een gegenereerd volgnummer.

REST. Magento’s REST implementatie is gebaseerd op afzonderlijke entiteiten. Het staat je niet toe om meerdere producten ineens te importeren, omdat het framework daar niet mee kan omgaan. Ik wilde toch Magento’s webapi authenticatie systeem gebruiken en meerdere producten importeren via XML. Met een kleine hack slaagde ik erin om dit te doen en dit stelt je in staat om te importereren via een REST call (alleen XML).

Veel plezier!

Je kunt deze library gebruiken om je maatwerk product import te schrijven. Het streeft ernaar de snelste Magento 2 product import library te zijn, het valideert input en geeft goede feedback bij fouten, het heeft een uitgebreide API en ik heb elk deel ervan gedocumenteerd.

NB: de library is erg nieuw en slechts gebruikt in enkele projecten. Veel features zijn nog niet gebruikt in productie-omgevingen. Begin ermee in een veilige omgeving met een backup van de database. Je zult zeker tegen fouten aanlopen, omdat het gaat om veel nieuwe code. Rapporteer deze in de issues sectie van de GitHub repository en ik zal er naar kijken.

Ik hoop dat je dit een prettige library vindt. Ik sta open voor alle constructieve feedback. Laat me weten welke onderdelen van de library je hebt gebruikt en wat er aan verbeterd kan worden.

Reacties:

  1. Peter at 13:02

    Hoi Patrick,

    Kan ik deze ook gebruiken een vervanger voor MagMi aangezien er geen MagMi voor M2 is. Werkt dit ook voor Magento 2.3 want ik begreep dat daar de database gewijzigd was?

    • Patrick at 10:12

      Dag Peter,

      Onze extensie heeft inderdaad dezelfde insteek om op database-niveau producten te importeren vanwege snelheid, dus is daarmee vergelijkbaar met MagMi. De extensie is ook compatible gemaakt met Magento 2.3 (m.n. MSI).

      Er is overigens wel een initiatief om MagMi te porten naar Magento 2: https://github.com/macopedia/magmi-m2 , maar ik heb de indruk dat het nog niet erg compleet is.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.