ElasticSearch - latin characters

Help for integrating the Laravel package
Forum rules
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
kdim95
Advanced
Posts: 208
Joined: 26 Aug 2022, 12:17

ElasticSearch - latin characters

Post by kdim95 » 01 Aug 2023, 12:15

Laravel framework version: 10.16.1
Aimeos Laravel version: 2023.04.*
PHP Version: 8.2.8
Environment: Linux

Hello,

I have the ai-elastic plugin.

I want to be able to search for products in cyrillic, but also to be able to find them again if the user uses latin characters to write cyrillic. For example the user types "kniga" instead of "книга" in bulgarian.

What's the best way to do this?

User avatar
aimeos
Administrator
Posts: 7917
Joined: 01 Jan 1970, 00:00

Re: ElasticSearch - latin characters

Post by aimeos » 02 Aug 2023, 15:26

Don't know if ElasticSearch supports transliteration of characters at all, Solr may be able to do that.
You have to check the ES documentation to see if you find something but in Aimeos it's not available by default.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

kdim95
Advanced
Posts: 208
Joined: 26 Aug 2022, 12:17

Re: ElasticSearch - latin characters

Post by kdim95 » 02 Aug 2023, 16:13

I came up with one solution, but your feedback would also be appreciated:
  • What do you think of my solution?
  • Is the "fuzziness" of the search affected compared to searching for the original label?
  • Is there any better solution than what I've come up with?
Solution:

I have overriden this method:
Aimeos\MShop\Index\Manager\Text\Elastic::hydrate()

I have added this line:
$map['content'][] = Str::ascii( $map['name'] );

This adds the title of the product transliterated.

I used the Laravel String helper for the transliteration:
use Illuminate\Support\Str;

For this to work, the products need to be indexed again:
php artisan aimeos:jobs index/rebuild

Please guide me as to how to override this file, because I've currently changed the original.
Should I host my own private version of the package, or is there a proper way to override it?

Code: Select all

	/**
	 * Adds more data from the items to the data entries
	 *
	 * @param \Aimeos\Map $items Product items implementing \Aimeos\MShop\Product\Item\Iface
	 * @param \Aimeos\Map $entries Associative list with product IDs as keys and product data as values
	 * @return \Aimeos\Map Associative list with product IDs as keys and hydrated product data as values
	 */
	public function hydrate( \Aimeos\Map $items, \Aimeos\Map $entries ) : \Aimeos\Map
	{
		$config = $this->context()->config();
		$types = $config->get( 'mshop/index/manager/text/types' );
		$attrTypes = $config->get( 'mshop/index/manager/text/attribute-types', ['variant', 'default'] );

		foreach( $items as $idx => $item )
		{
			$entry = $entries[$idx] ?? [];

			foreach( $this->call( 'getTexts', $item, $types, $attrTypes ) as $langId => $map )
			{
				$url = $map['url'] ?? $item->getName( 'url', $langId );

				if( !isset( $map['name'] ) ) {
					$map['content'][] = $map['name'] = $item->getLabel();
				}

				$map['content'][] = Str::ascii( $map['name'] );

				$entry['index.text:url(' . $langId . ')'] = $url;
				$entry['index.text:name(' . $langId . ')'] = $map['name'];
				$entry['index.text:content(' . $langId . ')'] = array_values( array_unique( $map['content'] ) );
			}

			$entries[$idx] = $entry;
		}

		foreach( $this->getSubManagers() as $submanager ) {
			$entries = $submanager->hydrate( $items, $entries );
		}

		return $entries;
	}

User avatar
aimeos
Administrator
Posts: 7917
Joined: 01 Jan 1970, 00:00

Re: ElasticSearch - latin characters

Post by aimeos » 04 Aug 2023, 05:14

Extend your new class which contains the hydrate() method from the original Elastic class and configure the name of your new class using:

Code: Select all

mshop/manager/index/text/name = '...'
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

kdim95
Advanced
Posts: 208
Joined: 26 Aug 2022, 12:17

Re: ElasticSearch - latin characters

Post by kdim95 » 14 Aug 2023, 12:00

Thanks, I got it working.

config/shop.php:

Code: Select all

	'mshop' => [
		'index' => [
			'manager' => [
				'text' => [
					'name' => 'ElasticCustom',
				],
			],
		],
	],
/packages/my-extension/src/MShop/Index/Manager/Text:

Code: Select all

<?php

namespace Aimeos\MShop\Index\Manager\Text;

class ElasticCustom
    extends Elastic
{
    /**
	 * Adds more data from the items to the data entries
	 *
	 * @param \Aimeos\Map $items Product items implementing \Aimeos\MShop\Product\Item\Iface
	 * @param \Aimeos\Map $entries Associative list with product IDs as keys and product data as values
	 * @return \Aimeos\Map Associative list with product IDs as keys and hydrated product data as values
	 */
	public function hydrate( \Aimeos\Map $items, \Aimeos\Map $entries ) : \Aimeos\Map
	{
		$config = $this->context()->config();
		$types = $config->get( 'mshop/index/manager/text/types' );
		$attrTypes = $config->get( 'mshop/index/manager/text/attribute-types', ['variant', 'default'] );

		foreach( $items as $idx => $item )
		{
			$entry = $entries[$idx] ?? [];

			foreach( $this->call( 'getTexts', $item, $types, $attrTypes ) as $langId => $map )
			{
				$url = $map['url'] ?? $item->getName( 'url', $langId );

				if( !isset( $map['name'] ) ) {
					$map['content'][] = $map['name'] = $item->getLabel();
				}

				$map['content'][] = Transliterate::to_ascii( $map['name'], 'bulgarian' );

				$entry['index.text:url(' . $langId . ')'] = $url;
				$entry['index.text:name(' . $langId . ')'] = $map['name'];
				$entry['index.text:content(' . $langId . ')'] = array_values( array_unique( $map['content'] ) );
			}

			$entries[$idx] = $entry;
		}

		foreach( $this->getSubManagers() as $submanager ) {
			$entries = $submanager->hydrate( $items, $entries );
		}

		return $entries;
	}
}

Post Reply