Индексирование в magento

38
Индексация в Magento Виктор Тихончук Magento System Architect

Upload: magecom-ukraine

Post on 22-May-2015

4.278 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Индексирование в Magento

Индексация в Magento

Виктор ТихончукMagento System Architect

Page 2: Индексирование в Magento

Модуль Mage_Index

События

Индекс

Индексатор

Процесс

Page 3: Индексирование в Magento

Событие

Mage_Index_Model_Event

Событие – то, что происходит в некоторый момент времени и рассматривается как изменение состояния сущности.

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

Типы изменений сущности (event type)• Сохранение (SAVE)

• Удаление (DELETE)

• Групповая обработка (MASS_ACTION)

Page 4: Индексирование в Magento

Обработчик

Mage_Index_Model_Indexer

• processEntityAction($entity, $entityType, $eventType)

• logEvent($entity, $entityType, $eventType)

• registerEvent(Mage_Index_Model_Event $event)

• indexEvent(Mage_Index_Model_Event $event)

• indexEvents($entity = null, $type = null)

Page 5: Индексирование в Magento

Изменения в абстрактной модели

Процесс сохранения• _getResource()->beginTransaction()

• _beforeSave()

• _getResource()->save()

• _afterSave()

• _getResource()->commit()

• afterCommitCallback()

Новые события• model_save_commit_after

• {eventPrefix}_save_commit_after

Page 6: Индексирование в Magento

Изменения в абстрактной модели

Процесс удаления• _getResource()->beginTransaction()

• _beforeDelete()

• _getResource()->delete()

• _afterDelete()

• _getResource()->commit()

• _afterDeleteCommit()

Новые события• model_delete_commit_after

• {eventPrefix}_delete_commit_after

Page 7: Индексирование в Magento

Сущности

• catalog/product (SAVE, DELETE, MASS_ACTION)

• catalog/category (SAVE, DELETE)

• catalog/resource_eav_attribute (SAVE, DELETE)

• customer/group (SAVE)

• cataloginventory/stock_item (SAVE)

• tag/tag (SAVE)

• core/store (SAVE, DELETE)

• core/store_group (SAVE, DELETE)

• core/website (SAVE, DELETE)

Page 8: Индексирование в Magento

Процессы и индексаторы

Индексатор может работать в 2х режимах:

• в режиме реального времени (MODE_REAL_TIME)

• в ручном режиме (MODE_MANUAL)

У каждого индексатора есть текущий статус:

• работает (STATUS_RUNNING)

• режим ожидания (STATUS_PENDING)

• необходимо перестроить (STATUS_REQUIRE_REINDEX)

REQUIRE_REINDEXMODE MANUAL

New Indexer

Событие

Page 9: Индексирование в Magento

Процесс

Mage_Index_Model_Process

• matchEvent(Mage_Index_Model_Event $event)

• register(Mage_Index_Model_Event $event)

• processEvent(Mage_Index_Model_Event $event)

• reindexAll()

• reindexEverything()

• indexEvents()

• changeStatus($status)

• getIndexer()

Page 10: Индексирование в Magento

CatalogInventory Stock Status

Цель оптимизировать затраты на подсчет возможности

покупки товара при отображении товаров в каталоге, поиске и т.д.

Мотивация для простых (simple) товаров - динамически определить

доступность не является трудозатратной операцией, чего не скажешь о составных (composite), для которых нужно учитывать статус всех его составляющих

Задача сделать предварительно подсчитанный статус для

каждого товара с учетом склада и веб сайта

Page 11: Индексирование в Magento

Шаг 1: Структура данных индекса

cataloginventory/stock_status

product_id

website_id

stock_id

qty

stock_status

Page 12: Индексирование в Magento

Шаг 2: Создаем индексатор

Mage_CatalogInventory_Model_Indexer_Stock

Page 13: Индексирование в Magento

Шаг 2: Создаем индексатор

Mage_CatalogInventory_Model_Indexer_Stock

Mage_Index_Model_Indexer_Abstract

Page 14: Индексирование в Magento

Шаг 2: Создаем индексатор

Mage_CatalogInventory_Model_Indexer_Stock

Mage_Core_Model_Abstract

Mage_Index_Model_Indexer_Abstract

Page 15: Индексирование в Magento

Шаг 2: Создаем индексатор

Mage_CatalogInventory_Model_Mysql4_Indexer_Stock

Mage_Core_Model_Mysql4_Abstract

Mage_Index_Model_Mysql4_Indexer_Abstract

Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Abstract

Page 16: Индексирование в Magento

Шаг 2: Создаем индексатор

Абстрактные методы индексатора• getName()

• getDescription()

• _registerEvent()

• _processEvent()

Page 17: Индексирование в Magento

Шаг 3: Событияprotected $_matchedEntities = array(    Mage_CatalogInventory_Model_Stock_Item::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE    ),    Mage_Catalog_Model_Product::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE,        Mage_Index_Model_Event::TYPE_MASS_ACTION,        Mage_Index_Model_Event::TYPE_DELETE    ),    Mage_Core_Model_Store::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE    ),    Mage_Core_Model_Store_Group::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE    ),    Mage_Core_Model_Config_Data::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE    ),    Mage_Catalog_Model_Convert_Adapter_Product::ENTITY => array(        Mage_Index_Model_Event::TYPE_SAVE    ));

Page 18: Индексирование в Magento

Шаг 4: Изменение конфигурацииprotected $_relatedConfigSettings = array(    Mage_CatalogInventory_Model_Stock_Item::XML_PATH_MANAGE_STOCK,    Mage_CatalogInventory_Helper_Data::XML_PATH_SHOW_OUT_OF_STOCK);

public function matchEvent(Mage_Index_Model_Event $event){ // check saved result in $event and return it if ($entity == Mage_Core_Model_Config_Data::ENTITY) { $configData = $event->getDataObject(); $path = $configData->getPath(); if (in_array($path, $this->_relatedConfigSettings)) { $result = $configData->isValueChanged(); } else { $result = false; } } else { $result = parent::matchEvent($event); } // save result in $event and return it}

Page 19: Индексирование в Magento

Шаг 5: Регистрация событияprotected function _registerEvent(Mage_Index_Model_Event $event){    switch ($event->getEntity()) {        case Mage_Catalog_Model_Product::ENTITY:            $this->_registerCatalogProductEvent($event);            break;  // skip some cases        case Mage_Core_Model_Store::ENTITY:        case Mage_Core_Model_Config_Data::ENTITY: $reindex = Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX;            $event->addNewData('skip_call_event_handler', true);            $process = $event->getProcess();            $process->changeStatus($reindex);             if ($event->getEntity() == Mage_Core_Model_Config_Data::ENTITY) {                $configData = $event->getDataObject(); $indexer = Mage::getSingleton('index/indexer');                if ($configData->getPath() == XML_PATH_SHOW_OUT_OF_STOCK) {                    $index->getProcessByCode('catalog_product_price')                        ->changeStatus($reindex);                    $indexer->getProcessByCode('catalog_product_attribute')                        ->changeStatus($reindex);                }            }            break;    }}

Page 20: Индексирование в Magento

Шаг 5: Регистрация событияprotected function _registerCatalogProductDeleteEvent (Mage_Index_Model_Event $event){    /** @var $product Mage_Catalog_Model_Product */    $product = $event->getDataObject();     $parentIds = $this->_getResource() ->getProductParentsByChild($product->getId());    if ($parentIds) {        $event->addNewData('reindex_stock_parent_ids', $parentIds);    }     return $this;}

Page 21: Индексирование в Magento

Шаг 6: Обработка событияprotected function _processEvent(Mage_Index_Model_Event $event){ $data = $event->getNewData(); if (!empty($data['cataloginventory_stock_reindex_all'])) { $this->reindexAll(); } if (empty($data['skip_call_event_handler'])) { $this->callEventHandler($event); }}

Page 22: Индексирование в Magento

Шаг 7: Ресурс модель

Resource Model

Type Indexer Interface

Type Indexer Default

Type Indexer Configurable

Page 23: Индексирование в Magento

Шаг 7: Ресурс модель protected function _getTypeIndexers() { if (is_null($this->_indexers)) { $this->_indexers = array(); $types = Mage::getSingleton('catalog/product_type') ->getTypesByPriority(); foreach ($types as $typeId => $typeInfo) { if (isset($typeInfo['stock_indexer'])) { $modelName = $typeInfo['stock_indexer']; } else { $modelName = $this->_defaultIndexer; } $isComposite = !empty($typeInfo['composite']); $indexer = Mage::getResourceModel($modelName) ->setTypeId($typeId) ->setIsComposite($isComposite);

$this->_indexers[$typeId] = $indexer; } } return $this->_indexers; }

Page 24: Индексирование в Magento

Шаг 7: Ресурс модель public function reindexAll() { $this->useIdxTable(true); $this->clearTemporaryIndexTable();

foreach ($this->_getTypeIndexers() as $indexer) { $indexer->reindexAll(); }

$this->syncData(); return $this; }

Page 25: Индексирование в Magento

Шаг 7: Ресурс модель public function catalogProductDelete(Mage_Index_Model_Event $event) { $data = $event->getNewData(); if (empty($data['reindex_stock_parent_ids'])) { return $this; }

$adapter = $this->_getWriteAdapter();

$parentIds = array(); foreach ($data['reindex_stock_parent_ids'] as $parentId => $parentType) { $parentIds[$parentType][$parentId] = $parentId; }

$adapter->beginTransaction(); try { foreach ($parentIds as $parentType => $entityIds) { $this->_getIndexer($parentType)->reindexEntity($entityIds); } } catch (Exception $e) { $adapter->rollback(); throw $e; }

$adapter->commit();

return $this; }

Page 26: Индексирование в Magento

Шаг 8: Ресурс модели (TYPE Default) public function setTypeId($typeId) { $this->_typeId = $typeId; return $this; }

public function getTypeId() { if (is_null($this->_typeId)) { Mage::throwException(Mage::helper('cataloginventory') ->__('Undefined product type.')); } return $this->_typeId; } public function reindexAll() { $this->useIdxTable(true); $this->_prepareIndexTable(); return $this; } public function reindexEntity($entityIds) { $this->_updateIndex($entityIds); return $this; }

Page 27: Индексирование в Magento

Шаг 9: Декларация индексатора<config> <!-- ... --> <global> <!-- ... --> <index> <indexer> <cataloginventory_stock> <model>cataloginventory/indexer_stock</model> </cataloginventory_stock> <catalog_product_attribute> <depends> <cataloginventory_stock /> </depends> </catalog_product_attribute> <catalog_product_price> <depends> <cataloginventory_stock /> </depends> </catalog_product_price> </indexer> </index> </global></config>

Page 28: Индексирование в Magento

Индекс цен для B2B

Цель Создать новый тип товара B2B

Справка В2В – сокращение от английских слов «business to business»,

в буквальном переводе – бизнес для бизнеса. Это сектор рынка, который работает не на конечного, рядового потребителя, а на такие же компании, то есть на другой бизнес.

Задача Новый тип товара, который наследует поведение простого

товара (simple), но имеет возможность указать цену для каждой группы пользователей (customer group)

Page 29: Индексирование в Magento

Индекс цен для B2B

public function reindexAll();public function reindexEntity($entityIds);public function registerEvent(Mage_Index_Model_Event $event);

Знакомство с интерфейсом Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Interface

Создаем свой индексатор

class Mageconf_B2b_Model_Mysql4_Indexer_Price extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Default{}

Page 30: Индексирование в Magento

Индекс цен для B2B

public function reindexAll(){ $this->useIdxTable(true); $this->_prepareFinalPriceData(); $this->_applyCustomOption(); $this->_movePriceDataToIndexTable(); return $this;}

public function reindexEntity($entityIds){ $this->_prepareFinalPriceData($entityIds); $this->_applyCustomOption(); $this->_movePriceDataToIndexTable();

return $this;}

Знакомство с … Indexer_Price_Default

Page 31: Индексирование в Magento

Индекс цен для B2B

protected function _getDefaultFinalPriceTable(){ if ($this->useIdxTable()) { return $this->getTable('catalog/product_price_indexer_final_idx'); } return $this->getTable('catalog/product_price_indexer_final_tmp');}

Page 32: Индексирование в Magento

Индекс цен для B2Bcatalog/product_price_indexer_final_*

entity_id

customer_group_id

website_id

tax_class_id

orig_price

price

min_price

max_price

tier_price

base_tier

Page 33: Индексирование в Magento

Индекс цен для B2Bprotected function _prepareFinalPriceData($entityIds = null){ // удаляем данные из таблицы, если они есть $this->_prepareDefaultFinalPriceTable();

$write = $this->_getWriteAdapter(); $select = $write->select() ->from(array('e' => $this->getTable('catalog/product')), array('entity_id')) ->joinCross( array('cg' => $this->getTable('customer/customer_group')), array('customer_group_id')) ->joinCross( array('cw' => $this->getTable('core/website')), array('website_id')) ->join( array('cwd' => $this->_getWebsiteDateTable()), 'cw.website_id = cwd.website_id', array()) ->join( array('csg' => $this->getTable('core/store_group')), 'csg.website_id = cw.website_id AND cw.default_group_id = csg.group_id', array()) ->join( array('cs' => $this->getTable('core/store')), 'csg.default_store_id = cs.store_id AND cs.store_id != 0', array()); // next slide

Page 34: Индексирование в Magento

Индекс цен для B2B // protected function _prepareFinalPriceData($entityIds = null) $select ->join( array('pw' => $this->getTable('catalog/product_website')), 'pw.product_id = e.entity_id AND pw.website_id = cw.website_id', array()) ->joinLeft( array('tp' => $this->_getTierPriceIndexTable()), 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id' . ' AND tp.customer_group_id = cg.customer_group_id', array()) ->join( array('b2d' => $this->getTable('b2b/price')), 'b2d.entity_id = e.entity_id AND b2d.customer IS NULL AND website_id=0' array()) ->join( array('b2w' => $this->getTable('b2b/price')), 'b2w.entity_id = e.entity_id AND b2w.customer = cg.customer_group_id' . ' AND b2w.website_id = cw.website_id', array()) ->where('e.type_id=?', $this->getTypeId());

$statusCond = $write->quoteInto('=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED); $this->_addAttributeToSelect($select, 'status', 'e.entity_id', 'cs.store_id', $statusCond, true);

Page 35: Индексирование в Magento

Индекс цен для B2B // protected function _prepareFinalPriceData($entityIds = null)

$taxClassId = $this->_addAttributeToSelect($select, 'tax_class_id', 'e.entity_id', 'cs.store_id'); $select->columns(array('tax_class_id' => $taxClassId));

$finalPrice = new Zend_Db_Expr('IFNULL(b2w.price, b2d.price)');

$select->columns(array( 'orig_price' => $price, 'price' => $finalPrice, 'min_price' => $finalPrice, 'max_price' => $finalPrice, 'tier_price' => new Zend_Db_Expr('NULL'), 'base_tier' => new Zend_Db_Expr('NULL'), ));

if (!is_null($entityIds)) { $select->where('e.entity_id IN(?)', $entityIds); }

Page 36: Индексирование в Magento

Индекс цен для B2B // protected function _prepareFinalPriceData($entityIds = null)

Mage::dispatchEvent('prepare_catalog_product_index_select', array( 'select' => $select, 'entity_field' => new Zend_Db_Expr('e.entity_id'), 'website_field' => new Zend_Db_Expr('cw.website_id'), 'store_field' => new Zend_Db_Expr('cs.store_id') ));

$query = $select->insertromSelect($this->_getDefaultFinalPriceTable()); $write->query($query);

return $this;}

public function registerEvent(Mage_Index_Model_Event $event){ $entity = $event->getEntity(); if ($entity == Mage_Catalog_Model_Product::ENTITY) { if ($event->getType() == Mage_Index_Model_Event::TYPE_SAVE) { // check attributes // add data to event } }}

Page 37: Индексирование в Magento

Обзор индексаторов в Magento

• Product Attributes

• Product Prices

• Catalog URL Rewrites

• Product Flat Data

• Category Flat Data

• Category Products

• Catalog Search Index

• Stock Status

• Tag Aggregation Data

Page 38: Индексирование в Magento

Спасибо за вниманиеEmail: [email protected]