7

Under app/code/Magento/CatalogSearch/etc/ there's a search_request.xml file with the following content:

<requests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="urn:magento:framework:Search/etc/search_request.xsd">
    <request query="quick_search_container" index="catalogsearch_fulltext">
        <dimensions>
            <dimension name="scope" value="default"/>
        </dimensions>
        <queries>
            <query xsi:type="boolQuery" name="quick_search_container" boost="1">
                <queryReference clause="should" ref="search" />
                <queryReference clause="must" ref="category"/>
                <queryReference clause="must" ref="price"/>
                <queryReference clause="must" ref="visibility"/>
            </query>
            <query xsi:type="matchQuery" value="$search_term$" name="search">
                <match field="sku"/>
                <match field="*"/>
            </query>
            <query xsi:type="filteredQuery" name="category">
                <filterReference clause="must" ref="category_filter"/>
            </query>
            <query xsi:type="filteredQuery" name="price">
                <filterReference clause="must" ref="price_filter"/>
            </query>
            <query xsi:type="filteredQuery" name="visibility">
                <filterReference clause="must" ref="visibility_filter"/>
            </query>
        </queries>
        <filters>
            <filter xsi:type="termFilter" name="category_filter" field="category_ids" value="$category_ids$"/>
            <filter xsi:type="rangeFilter" name="price_filter" field="price" from="$price.from$" to="$price.to$"/>
            <filter xsi:type="termFilter" name="visibility_filter" field="visibility" value="$visibility$"/>
        </filters>
        <aggregations>
            <bucket name="price_bucket" field="price" xsi:type="dynamicBucket" method="$price_dynamic_algorithm$">
                <metrics>
                    <metric type="count"/>
                </metrics>
            </bucket>
            <bucket name="category_bucket" field="category_ids" xsi:type="termBucket">
                <metrics>
                    <metric type="count"/>
                </metrics>
            </bucket>
        </aggregations>
        <from>0</from>
        <size>10000</size>
    </request>
    <request query="advanced_search_container" index="catalogsearch_fulltext">
        <dimensions>
            <dimension name="scope" value="default"/>
        </dimensions>
        <queries>
            <query xsi:type="boolQuery" name="advanced_search_container" boost="1">
                <queryReference clause="should" ref="sku_query"/>
                <queryReference clause="should" ref="price_query"/>
                <queryReference clause="should" ref="category_query"/>
            </query>
            <query name="sku_query" xsi:type="filteredQuery">
                <filterReference clause="must" ref="sku_query_filter"/>
            </query>
            <query name="price_query" xsi:type="filteredQuery">
                <filterReference clause="must" ref="price_query_filter"/>
            </query>
            <query name="category_query" xsi:type="filteredQuery">
                <filterReference clause="must" ref="category_filter"/>
            </query>
        </queries>
        <filters>
            <filter xsi:type="wildcardFilter" name="sku_query_filter" field="sku" value="$sku$"/>
            <filter xsi:type="rangeFilter" name="price_query_filter" field="price" from="$price.from$" to="$price.to$"/>
            <filter xsi:type="termFilter" name="category_filter" field="category_ids" value="$category_ids$"/>
        </filters>
        <from>0</from>
        <size>10000</size>
    </request>
    <request query="catalog_view_container" index="catalogsearch_fulltext">
        <dimensions>
            <dimension name="scope" value="default"/>
        </dimensions>
        <queries>
            <query xsi:type="boolQuery" name="catalog_view_container" boost="1">
                <queryReference clause="must" ref="category"/>
                <queryReference clause="must" ref="price"/>
                <queryReference clause="must" ref="visibility"/>
            </query>
            <query xsi:type="filteredQuery" name="category">
                <filterReference clause="must" ref="category_filter"/>
            </query>
            <query xsi:type="filteredQuery" name="price">
                <filterReference clause="must" ref="price_filter"/>
            </query>
            <query xsi:type="filteredQuery" name="visibility">
                <filterReference clause="must" ref="visibility_filter"/>
            </query>
        </queries>
        <filters>
            <filter xsi:type="termFilter" name="category_filter" field="category_ids" value="$category_ids$"/>
            <filter xsi:type="rangeFilter" name="price_filter" field="price" from="$price.from$" to="$price.to$"/>
            <filter xsi:type="termFilter" name="visibility_filter" field="visibility" value="$visibility$"/>
        </filters>
        <aggregations>
            <bucket name="price_bucket" field="price" xsi:type="dynamicBucket" method="$price_dynamic_algorithm$">
                <metrics>
                    <metric type="count"/>
                </metrics>
            </bucket>
            <bucket name="category_bucket" field="category_ids" xsi:type="termBucket">
                <metrics>
                    <metric type="count"/>
                </metrics>
            </bucket>
        </aggregations>
        <from>0</from>
        <size>10000</size>
    </request>
</requests>

I'm assuming it is used for the search, I'm wondering how Magento processes this file and what are the following fields used for:

  • request
  • dimensions
  • queries
  • filters
  • aggregations
  • from
  • size

2 Answers 2

14

Magento 2 provides a declarative way to describe search request which should be executed. search_request.xml is a part of Query API. This declaration describes:

  1. What index should be queried
  2. What full-text queries should be executed (queries section)
  3. What filters should be applied (filters section)
  4. For which attributes faceted search should be built (Layered Navigation in terms of Magento) (aggregations section)

Naming convention here is very similar to ElasticSearch. For example, if you will look at XSD file (Search/etc/search_request.xsd) you will see that there are three possible query types:

  1. Bool Query (analogue for Elasticsearch BoolQuery)
  2. Match Query (analogue for Elasticsearch Match Query)
  3. Filter Query (analogue for Elasticsearch Filtered Query)

There is presentation which describes Magento 2 new Search approach and architecture

For now Magento indexes just product data. And there are 3 scenarios (read 3 search queries for that data):

  1. Quick Search (<request query="quick_search_container" index="catalogsearch_fulltext">)
  2. Advanced Search (<request query="advanced_search_container" index="catalogsearch_fulltext">)
  3. Category View (<request query="catalog_view_container" index="catalogsearch_fulltext">). As Magento implies Category View scenatio - as a search query without full text query in it.
3
  • 1
    Be careful, Magento 2 ElasticSearch integration is limited and you will not be able to implement specific search request out of the box. Such as specific filter type, bucket size etc. Maybe it will be added in the next releases. Commented Aug 8, 2017 at 15:14
  • @FranckGarnier you can always do that (implement specific filter type, use dedicated analyzer etc.) customizing out of the box Magento 2 implementation. That's the role of developers who make Magento 2 customizations. Magento needs to provide enough extension points to make these customizations easy Commented Aug 9, 2017 at 18:08
  • Yes I did, but the Magento 2 interface is sometime time consuming to extend without breakchanges. Commented Aug 10, 2017 at 11:03
5

Looks like it's used to define attributes certain filters should be applied to and then searchable attributes are applied against this XML to configure the searchRequest - see:

Magento\CatalogSearch\Model\Search\RequestGenerator

private function generateRequest($attributeType, $container, $useFulltext)
{
    $request = [];
    foreach ($this->getSearchableAttributes() as $attribute) {
        if ($attribute->getData($attributeType)) {
            if (!in_array($attribute->getAttributeCode(), ['price', 'category_ids'])) {
                $queryName = $attribute->getAttributeCode() . '_query';

                $request['queries'][$container]['queryReference'][] = [
                    'clause' => 'should',
                    'ref' => $queryName,
                ];
                $filterName = $attribute->getAttributeCode() . self::FILTER_SUFFIX;
                $request['queries'][$queryName] = [
                    'name' => $queryName,
                    'type' => QueryInterface::TYPE_FILTER,
                    'filterReference' => [['ref' => $filterName]],
                ];
                $bucketName = $attribute->getAttributeCode() . self::BUCKET_SUFFIX;
                if ($attribute->getBackendType() == 'decimal') {
                    $request['filters'][$filterName] = [
                        'type' => FilterInterface::TYPE_RANGE,
                        'name' => $filterName,
                        'field' => $attribute->getAttributeCode(),
                        'from' => '$' . $attribute->getAttributeCode() . '.from$',
                        'to' => '$' . $attribute->getAttributeCode() . '.to$',
                    ];
                    $request['aggregations'][$bucketName] = [
                        'type' => BucketInterface::TYPE_DYNAMIC,
                        'name' => $bucketName,
                        'field' => $attribute->getAttributeCode(),
                        'method' => 'manual',
                        'metric' => [["type" => "count"]],
                    ];
                } else {
                    $request['filters'][$filterName] = [
                        'type' => FilterInterface::TYPE_TERM,
                        'name' => $filterName,
                        'field' => $attribute->getAttributeCode(),
                        'value' => '$' . $attribute->getAttributeCode() . '$',
                    ];
                    $request['aggregations'][$bucketName] = [
                        'type' => BucketInterface::TYPE_TERM,
                        'name' => $bucketName,
                        'field' => $attribute->getAttributeCode(),
                        'metric' => [["type" => "count"]],
                    ];
                }
            }
        }
        /** @var $attribute Attribute */
        if (in_array($attribute->getAttributeCode(), ['price', 'sku'])
            || !$attribute->getIsSearchable()
        ) {
            //same fields have special semantics
            continue;
        }
        if ($useFulltext) {
            $request['queries']['search']['match'][] = [
                'field' => $attribute->getAttributeCode(),
                'boost' => $attribute->getSearchWeight() ?: 1,
            ];
        }
    }
    return $request;
}
1
  • yes, this request generator adds dynamic searchable attributes and filters/layered nav for them at a time of reading search_request.xml , because product attributes could be added/removed/changed dynamically by merchant, so it's not possible to specify filters by these attributes in advanced. Commented May 12, 2016 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.