0

I would like to add ngram in my elastic search. https://www.elastic.co/guide/en/elasticsearch/guide/current/ngrams-compound-words.html

I had tried this at Magento\Elasticsearch\Model\Adapter\Elasticsearch.php:

/**
 * Create new index with mapping.
 *
 * @param int $storeId
 * @param string $indexName
 * @param string $mappedIndexerId
 * @return $this
 */
protected function prepareIndex($storeId, $indexName, $mappedIndexerId)
{
    $this->indexBuilder->setStoreId($storeId);
    $settings = $this->indexBuilder->build();
    $allAttributeTypes = $this->fieldMapper->getAllAttributesTypes([
        'entityType' => $mappedIndexerId,
        // Use store id instead of website id from context for save existing fields mapping.
        // In future websiteId will be eliminated due to index stored per store
        'websiteId' => $storeId
    ]);
    $settings['index']['mapping']['total_fields']['limit'] = $this->getMappingTotalFieldsLimit($allAttributeTypes);

    $settings['index']['analysis']['filter']['trigrams_filter'] = [
        'type' => 'ngram',
        'min_gram' => 3,
        'max_gram' => 3
    ];
    $settings['index']['analysis']['analyzer']['trigrams'] = [
        'type' => 'custom',
        'tokenizer' => 'standard',
        'filter' => [
            'lowercase', 'trigrams_filter'
        ]
    ];
    $mappings['product']['properties']['name'] = [
        'type' => 'text',
        'analyzer' => 'trigrams'
    ];
    $this->client->createIndex($indexName, ['settings' => $settings, 'mappings' => $mappings]);

    $this->client->addFieldsMapping(
        $allAttributeTypes,
        $indexName,
        $this->clientConfig->getEntityType()
    );
    $this->preparedIndex[$storeId] = $indexName;
    return $this;
}

But this returns following error:

report.CRITICAL: {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Rejecting mapping update to [254407_product_1_v61] as the final mapping would have more than 1 type: [product, document]"}],"type":"illegal_argument_exception","reason":"Rejecting mapping update to [254407_product_1_v61] as the final mapping would have more than 1 type: [product, document]"},"status":400} {"exception":"[object] (Elasticsearch\Common\Exceptions\BadRequest400Exception(code: 400): {\"error\":{\"root_cause\":[{\"type\":\"illegal_argument_exception\",\"reason\":\"Rejecting mapping update to [254407_product_1_v61] as the final mapping would have more than 1 type: [product, document]\"}],\"type\":\"illegal_argument_exception\",\"reason\":\"Rejecting mapping update to [254407_product_1_v61] as the final mapping would have more than 1 type: [product, document]\"},\"status\":400} at /vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php:636)"} []

Any suggestions?

0

Try to change.

$mappings['product']['properties']['name'] = [
        'type' => 'text',
        'analyzer' => 'trigrams'
    ];

Replace above code with a statement.

$mappings['document']['properties']['name'] = [
            'type' => 'text',
            'analyzer' => 'trigrams'
        ];

The above code(mentioned in your qn.) may only use for ElasticSearch 2.x,

Refer below code for ElasticSearch 6.x.

protected function prepareIndex($storeId, $indexName, $mappedIndexerId)
{
    $this->indexBuilder->setStoreId($storeId);
    $settings = $this->indexBuilder->build();
    $allAttributeTypes = $this->fieldMapper->getAllAttributesTypes([
        'entityType' => $mappedIndexerId,
        // Use store id instead of website id from context for save existing fields mapping.
        // In future websiteId will be eliminated due to index stored per store
        'websiteId' => $storeId
    ]);
    $settings['index']['mapping']['total_fields']['limit'] = $this->getMappingTotalFieldsLimit($allAttributeTypes);
    $settings['index']['analysis']['filter']['trigrams_filter'] = [
        'type' => 'ngram',
        'min_gram' => 3,
        'max_gram' => 3
    ];
    $settings['index']['analysis']['analyzer']['trigrams'] = [
        'type' => 'custom',
        'tokenizer' => 'standard',
        'filter' => [
            'lowercase', 'trigrams_filter'
        ]
    ];

    $this->client->createIndex($indexName, ['settings' => $settings]);
    $this->client->addFieldsMapping(
        $allAttributeTypes,
        $indexName,
        $this->clientConfig->getEntityType()
    );
    $this->preparedIndex[$storeId] = $indexName;
    return $this;
}

EDIT

You may have to make a change in a Builder.php.

$tokenizer = [
    'default_tokenizer' => [
        'type' => 'standard'
    ],
];

Replace the above code with below statement.

$tokenizer = [
    'default_tokenizer' => [
        'type' => 'ngram'
    ],
];
5
  • Thanks for the answer but getting this error: Catalog Search indexer process unknown error: {"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"Root mapping definition has unsupported parameters: [analysis : {analyzer={custom_analyzer={tokenizer=trigrams_tokenizer}}, tokenizer={trigrams_tokenizer={token_chars=[letter], min_gram=3, type=ngram, ..... – Adarsh Khatri Dec 31 '19 at 4:29
  • @AdarshKhatri which ES version you use? – sandip Dec 31 '19 at 4:49
  • ES version 6.8.5 – Adarsh Khatri Dec 31 '19 at 4:51
  • check the updated answer. – sandip Dec 31 '19 at 5:03
  • Thanks, now reindex is running without any error. But my main motto of this to do a partial search. It's still not giving any results. See this: magento.stackexchange.com/questions/299311/… – Adarsh Khatri Dec 31 '19 at 5:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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