Как работать с файлами отчетов Amazon (идентификаторы asin ...) - PullRequest
1 голос
/ 30 марта 2019

CSV-файлы выглядят так

Stock

asin          name         quantiy
----------------------------------
B01EI65LTI    Blue Shoes   20
B079VGHTM2    Black Shoes  10
B07B33J5CK    Green Shoes  3

Storage fees

asin        currency   estimated-monthly-storage-fee
----------------------------------------------------
B01EI65LTI  EUR        0.7988
B079VGHTM2  GBP        0.4656
B07B33J5CK  EUR        0.1264

Sales

amazon-order-id        asin        quantity    item-price
----------------------------------------------------------
404-2135868-6928346    B01EI65LTI  1           59.95
402-0310960-9618709    B079VGHTM2  1           18.95
403-6094647-7799558    B07B33J5CK  1           14.95    

В настоящее время мое решение заключается в добавлении дополнительных идентификаторов и ассоциаций к субъекты, например, складские и складские расходы

/**
 * @ORM\Entity(repositoryClass="App\Repository\StockRepository")
 * @ORM\Table(indexes={@ORM\Index(name="asin_idx", columns={"asin"})})
 */
class Stock
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /** @ORM\Column(type="string", length=16) */
    private $asin;

    /** @ORM\Column(type="string", length=255) */
    private $productName;

    /** @ORM\Column(type="integer") */
    private $afnWarehouseQuantity;

    /**
     * @OneToOne(targetEntity="StorageFee")
     * @JoinColumn(name="storageFeeId", referencedColumnName="id")
     */
    private $storageFee;    
}

/** @ORM\Entity(repositoryClass="App\Repository\StorageFeeRepository") */
class StorageFee
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /** @ORM\Column(type="string", length=16) */
    private $asin;

    /** @ORM\Column(type="string", length=8) */
    private $currency;

    /** @ORM\Column(type="float") */
    private $estimatedMonthlyStorageFee;
}

и "массовая вставка" сущностей

class StockRepository extends ServiceEntityRepository 
{
    public function insertFromFile(string $fileName)
    { 
        $this->getEntityManager()->getConnection()
             ->getConfiguration()->setSQLLogger(null);

        // read csv...
        foreach ($csv as $row) {

            $stock = (new Stock())
                ->setAsin($row['asin'])
                ->setName($row['name'])
                ->setQuantity($row['quantity'])
            ;

            $this->getEntityManager()->persist($stock);

            if (($numInsert % $20) === 0) {
                $this->getEntityManager()->flush();
                $this->getEntityManager()->clear();
            }
        }

        $this->getEntityManager()->flush(); // flush remaining
        $this->getEntityManager()->clear();
    }
}

и «массовое обновление» ассоциации на шаге secound.

public function updateAssociation()
{
    $this->getEntityManager()->getConnection()
         ->getConfiguration()->setSQLLogger(null);

    $query = $this->getEntityManager()->createQuery('SELECT sf.id, sf.asin FROM App\Entity\StorageFee sf');
    $storageFees = $query->getResult();

    $query = $this->getEntityManager()->createQuery('UPDATE App\Entity\Stock s SET s.storageFee = :id WHERE s.asin = :asin');

    foreach ($storageFees as $row) {
        $query->setParameter('id', $row['id'])
              ->setParameter('asin', $row['asin']);
        $query->execute();
    }
}

Я старался изо всех сил, но с этими большими файлами (до 35 000 строк) У меня все еще очень долгий срок выполнения сценария - 20-40 секунд. И установить ассоциации на втором этапе выглядят не очень «профессионально». Я думаю. Но смешивание вставки и обновлений со временем выполнения +60 секунд (?) тоже проблема.

Может быть, у меня неправильная концепция. Рекомендуется использовать здесь существующий асин как ключ? Никогда раньше не работал со строковыми ключами ... и еще не очень много сделали с доктриной.

Я был бы очень рад любому предложению. Спасибо и наилучшими пожеланиями

1 Ответ

1 голос
/ 30 марта 2019

Относительно Jakumi - я обновил свой код, и он в два раза быстрее с одним шагом в правильном порядке импорта.(размер пакета 200 означает более высокое пиковое использование памяти)

class StockRepository extends ServiceEntityRepository 
{
    public function insertFromFile(string $fileName)
    { 
        $this->getEntityManager()->getConnection()
             ->getConfiguration()->setSQLLogger(null);

        // get storeage fee ids
        $query = $this->getEntityManager()
            ->createQuery(/** @lang DQL */'
                SELECT sf.id, sf.asin 
                 FROM App\Entity\StorageFee sf
        ');

        $map = [];
        foreach($query->getResult() as $row) {
            $map[$row['asin']] = $row['id'];
        }


        // read csv...
        foreach ($csv as $row) {

            $stock = (new Stock())
                ->setAsin($row['asin'])
                ->setName($row['name'])
                ->setQuantity($row['quantity'])
            ;

            // add reference
            if (isset($map[$row['asin']])) {
                $storageFee = $this->getEntityManager()->getReference('App\Entity\StorageFee', $map[$row['asin']]);
                $stock->setStorageFee($storageFee);
            }

            $this->getEntityManager()->persist($stock);

            if (($numInsert % 200) === 0) {
                $this->getEntityManager()->flush();
                $this->getEntityManager()->clear();
            }
        }

        $this->getEntityManager()->flush(); // flush remaining
        $this->getEntityManager()->clear();
    }
}
...