Suche "reparieren"

Hallo Community,

zum Problem, die Standard-Volltextsuche liefert haufenweise Artikel, in denen der Suchbegriff gar nicht vorkommt!

Also habe ich hier im Forum stunden lang nach einer Lösung gesucht.
Gefunden habe ich im Großen und Ganzen lediglich Beiträge, in dem die Leute über das o.g. Verhaltgen abkotzen. Lösungsvorschläge per Konfiguration oder per Anpassung der Programmierung Fehlanzeige.
Von Shopware selbst kein einziger Hinweis darauf, wie die Suche arbeitet und wie sie sich modifizieren ließe.

In einem Beitrag gab es dann doch einen Hinweis, wo in der Programmierung die Suchbegriffe für die SQL-Query vorbereitet werden (ProductSearchTermInterpreter.php).

Darin habe ich per Debug-Ausgabe mit einem Suchbegriff getestet, welcher nicht im Shop meines Kunden vorkommt „regal“. Aus dem Suchbegriff werden diverse Varianten für die SQL Abfrage generiert:

[regal] => [
	[normal] => [
		[0] => rgal%
		[1] => r_gal%
		[2] => r__gal%
		[3] => ral%
		[4] => r_al%
		[5] => r__al%
		[6] => regl%
		[7] => reg_l%
		[8] => reg__l%
		[9] => reg%
		[10] => reg_%
		[11] => reg__%
	],
	[reversed] => [
		[0] => lger%
		[1] => l_ger%
		[2] => l__ger%
		[3] => ler%
		[4] => l_er%
		[5] => l__er%
		[6] => lagr%
		[7] => lag_r%
		[8] => lag__r%
		[9] => lag%
		[10] => lag_%
		[11] => lag__%
	]
]

Die Suche findet 136 Ergebnisse, obwohl der Suchbgeriff auf keiner der Artikelseiten vorkommt.
Es werde Artikel von z. B. „Max Reger“ gefunden, was wiederum logisch, jedoch nicht gewünscht ist.
Ein exaktes Suchergebnis, nach z. B. einer Artikelnumer, wie „BR 100 289“ ist mit der Suche nicht möglich!

Ich frage mich, was der Quatsch soll?
Außerdem erschließt sich mir die Funktion des „reversed“-Blocks nicht.
Damit ist klar, warum die Suche haufenweise Produkte liefert, in denen der Suchbegriff nicht vorkommt.

Also habe ich die Umwandlung der Suchbegriffe auf das Wesentliche eingedampft, damit folgenden generiert wird:

[regal] => [
    [normal] => [
        [0] => regal%
    ]
    [reversed] => [ ]
]

Und Voilá die Suche macht, was sie soll!

Mit „regal“ wird kein Artikel gefunden und alle anderen Suchanfragen, in denen Suchbegriffe verwendet werden, die im Shop vorkommen liefern die gewünschten Ergebnisse.

Damit das wie oben funktioniert, habe ich in der Funktion „slop“ die foreach-Schleife wie folgt eingedampft:

foreach ($tokens as $token) {
	$slops = [
		'normal' => [],
		'reversed' => [],
	];
	$token = (string) $token;

	$slops['normal'][] = $token . '%';
	$slops['reversed'][] = "";
	$tokenSlops[$token] = $slops;
}

Anmerkung zur Konfiguration der Suche: Verknüpfung der Suchbegriffe steht auf „UND“ und bei Produktnummer ist „Suchbegriffe trennen“ angehakt.

Mein Problem ist nun, dass meine Modifikation im Code natürlich nicht update-sicher ist.

Hat mir jemand einen Hinweis, wie ich die Funktion „slop“ von ProductSearchTermInterpreter.php überschreiben update-sicher überschreiben kann?

Danke!

4 „Gefällt mir“

Hallo,

so wie ich das sehe, kann man den Service dekorieren.

Hier ein Bsp. für den ProductSearchBuilder

Service:

        <service id="MoorlProductSearchBuilder\Core\Content\Product\SearchKeyword\ProductSearchBuilder"
                 decorates="Shopware\Core\Content\Product\SearchKeyword\ProductSearchBuilderInterface"
                 decoration-priority="-1000"
                 public="true">
            <argument type="service"
                      id="MoorlProductSearchBuilder\Core\Content\Product\SearchKeyword\ProductSearchBuilder.inner"/>
        </service>

PHP:

<?php declare(strict_types=1);

namespace MoorlProductSearchBuilder\Core\Content\Product\SearchKeyword;

use Shopware\Core\Content\Product\SearchKeyword\ProductSearchBuilderInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Request;

class ProductSearchBuilder implements ProductSearchBuilderInterface
{
    private ProductSearchBuilderInterface $decorated;

    public function __construct(ProductSearchBuilderInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    /**
     * @param Request $request
     * @param Criteria $criteria
     * @param SalesChannelContext $context
     * @throws \Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException
     *
     * If Numbers are in search, then do not split string
     */
    public function build(Request $request, Criteria $criteria, SalesChannelContext $context): void
    {
        $search = trim($request->get('search'));

        // Remove double whitespaces
        $search = preg_replace('/\s+/', ' ', $search);

        // Remove special chars
        $search = preg_replace('/[^A-Za-z0-9\s]/', '', $search);

        // Split term
        $searchTerms = explode(" ", $search);
        $search = "";
        $hasNumber = false;

        foreach ($searchTerms as $searchTerm) {
            if ($this->countNonDigits($searchTerm) > 2) {
                $search .= $searchTerm . " ";
            } else {
                $hasNumber = true;
                $search .= $searchTerm;
            }
        }

        $search = trim($search);

        if ($hasNumber && count(explode(" ", $search)) == 1) {
            $criteria->addFilter(new EqualsFilter('product.searchKeywords.keyword', $search));
            return;
        }

        $request->query->set('search', $search);

        $this->decorated->build($request, $criteria, $context);
    }

    private function countNonDigits(string $search): int
    {
        return preg_match_all("/[\D+]/", $search);
    }

    private function countDigits(string $search): int
    {
        return preg_match_all("/[0-9]/", $search);
    }

    private function countWhitespaces(string $search): int
    {
        return preg_match_all("/[\s+]/", $search);
    }
}
1 „Gefällt mir“

Danke für die Hinweise hier! Wir haben uns mal die Mühe gemacht, um diese bescheuerte slop()-Methode gerade zu biegen. Leider hat der ProductSearchTermInterpreter eine einzige public function, weshalb man effektiv den restlichen Code 1:1 kopieren muss. Weder Vererbung noch Decorating hilft da weiter.