Bonjour,

J'ai créé un moteur de recherches avec ElasticSearch. Ci joint le code produit.

Dans mon index Elastic Search, j'ai 2 pois :
C La Coiffure
Astrid Coiffure

J'ai lancé une recherche "Astrid coiffure"

Je voudrais que Astrid coiffure sorte avant C La Coiffure, tu peux m'aider ? Si les 2 mots recherchés sont dans un des résultats, son score devrait avoir un poids plus important.

Merci de votre aide.

    public function searchPois($search, $size = 1000, $from = 0): array
    {
        $queryParameters['index'] = ['pois'];
        $queryParameters['body']['size'] = $size;
        $queryParameters['body']['from'] = $from;
        $queryParameters['body']['sort']['_score'] = ['order' => 'desc'];

        if (!empty($this->sortEnterpriseElasticScript())) {
            $queryParameters['body']['query']['function_score'] = $this->sortEnterpriseElasticScript();
        }

        if ($search->what->exactSearch) {
            $queryParameters['body']['query']['function_score']['query']['bool']['must'][0]['match_phrase']['name']['query'] = implode(' ', $search->what->tags);
        } else {
            if ($search->what->tags) {
                $search->what->tags = $this->removeUnsedWords($search->what->tags);

                if (count($search->what->tags) === 1) {
                    $tag = Tag::query()
                        ->where([
                            'type' => 'poi',
                            'slug' => str($search->what->tags[0])->slug()->value()
                        ])
                        ->first();

                    if ($tag) {
                        $term = [
                            'term' => [
                                'tags.id' => $tag->id,
                            ],
                        ];

                        $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;

                        $search->what->tags[0] = $tag->name;
                    } else {
                        $queryParameters['body']['query']['function_score']['query']['bool']['must'][0]['match']['name']['query'] = implode(' ', $search->what->tags);
                    }
                } else {
                    $queryParameters['body']['query']['function_score']['query']['bool']['must'][0]['match']['name']['query'] = implode(' ', $search->what->tags);
                }
            }

            if ($search->what->category) {
                $term = [
                    'term' => [
                        'categories.id' => $search->what->category->id,
                    ],
                ];

                $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
            } elseif ($search->what->subcategory) {
                $term = [
                    'term' => [
                        'subcategories.id' => $search->what->subcategory->id,
                    ],
                ];

                $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
            } elseif ($search->what->firm) {
                $term = [
                    'term' => [
                        'firm_id' => $search->what->firm->id,
                    ],
                ];

                $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
            }

            if ($search->where->address) {
                $term = [
                    'term' => [
                        'address_keyword' => $search->where->address,
                    ],
                ];

                $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
            }
        }

        if ($search->where->metro) {
            $term = [
                'term' => [
                    'metros.id' => $search->where->metro->id,
                ],
            ];

            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
        } elseif ($search->where->listOfAroundCities->isNotEmpty()) {
            $terms = [
                'terms' => [
                    'city.id' => $search->where->listOfAroundCities->pluck('id')->toArray(),
                ],
            ];

            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $terms;
        } elseif ($search->where->city) {
            $term = [
                'term' => [
                    'city.id' => $search->where->city->id,
                ],
            ];

            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
        } elseif ($search->where->department) {
            $term = [
                'term' => [
                    'department.id' => $search->where->department->id,
                ],
            ];

            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = $term;
        }

        if ($search->withPromotion) {
            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = [
                'exists' => [
                    'field' => 'promotion'
                ]
            ];
        }

        if ($search->atHome) {
            $queryParameters['body']['query']['function_score']['query']['bool']['must'][] = [
                'term' => [
                    'at_home' => true
                ]
            ];
        }

        return $this
            ->client
            ->search($queryParameters)
            ->asArray();
    }

    private function sortEnterpriseElasticScript(): array
    {
        $painlessScript = "
            double score = 0;
            double note = doc.containsKey('average') && !doc['average'].empty ? doc['average'].value : 0;
            double numberOfNotes = doc.containsKey('number_of_notes') && !doc['number_of_notes'].empty ? doc['number_of_notes'].value : 0;
            double reduceScore = 1;
            double coefficientIfIsSelected = doc.containsKey('selected') && doc['selected'].value ? 50 : 0;
            if (note <= 3.5) { reduceScore = 10; }
            double increaseScore = (numberOfNotes >= 5 && note >= 4) ? 5 : 1;
            score = ((numberOfNotes / params.numberOfReviews) / reduceScore + (note * increaseScore / params.numberOfNotes) * params.multiplyingFactor) + coefficientIfIsSelected;
            return score;
        ";

        return [
            'script_score' => [
                'script' => [
                    'lang' => 'painless',
                    'source' => $painlessScript,
                    'params' => [
                        'numberOfReviews' => 1, // ??
                        'numberOfNotes' => 1, // ??
                        'multiplyingFactor' => 2,
                    ],
                ],
            ],
        ];
    }

4 réponses


Hello :)

Alors si tu veux que Astrid sorte avant pour que ce soit par ordre alphabetique, dans la query du search il faudrait ajouter un orderBy("name") (name = nom de la colonne a trier)

Bonjour,

Non, je ne veux pas trier par AZ.

Je veux donner du poids si les termes recherchés sont dans le nom d'un POI.

Merci

Ah ok, alors tu peux faire orderByDesc("priority") (desc pour mettre en premier le plus gros poids)

Si tu appliques une priorité individuelle pour chaque ligne par contre ça risque d'être compliqué, le mieux ce serait des groupes de poids, comme ça tu peux avoir un poids de 1 a 5 par ex et plusieurs lignes peuvent avoir la même priorité

Si vraiment tu veux décider de l'ordre individuel de chaque product plus compliqué parce que si tu veux mettre un nouveau produit entre deux produit dont un a le poids 2 et l'autre le poids 3 ça va coincer, il faudra faire une nouvelle table product_priorities (arranges le nom de la collone pour que ça soit cohérent avec le projet) ensuite dedans tu mets une seule ligne qui sera un json qui contiendra les id des products

Coté code tu ajoutes un select Place After pour préciser la position de la nouvelle ligne dans le json, ensuite tu utilises ce json pour mapper de haut en bas les résultat dans l'ordre de ce tableau

Mais dans le code que j'ai fourni, ça se traduit par quelles modifications car c'est là que je coince.

Merci ;)