Commit 77a33a7b authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

MAJ de la recherche :

 - Modification des poids
 - Traitement du _ comme un tokenizer
 - Passage en query_string (Permet des recherches avec *)
 - Opérateur AND pour les recherches à plusieurs termes
parent 95f78d66
Loading
Loading
Loading
Loading
Loading
+13 −214
Original line number Diff line number Diff line
@@ -32,32 +32,21 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
        return [
            'settings' => [
                'analysis' => [
                    'tokenizer' => [
                        // Considérer les _ comme des séparateurs
                        'underscore_tokenizer' => [
                            'type' => 'pattern',
                            'pattern' => '[\W_]+'
                        ]
                    ],
                    'analyzer' => [
                        'folding_analyzer' => [
                            'tokenizer' => 'standard',
                            'tokenizer' => 'underscore_tokenizer',
                            'filter' => ['lowercase', 'asciifolding']
                        ]
                    ]
                ]
            ],
            /****
             * 'label' => $activity->getLabel(),
             * 'description' => $activity->getDescription(),
             * 'saic' => $activity->getCentaureId(),
             * 'numerotation' => $activity->getNumbers(),
             * 'oscar' => $activity->getOscarNum(),
             * 'activitytype' => $activity->getActivityType() ? (string)$activity->getActivityType() : '',
             * 'numbers' => implode(" ", $activity->getNumbersValues()),
             * 'eotp' => $activity->getCodeEOTP(),
             * 'acronym' => $activity->getAcronym(),
             * 'activity_id' => $activity->getId(),
             * 'disciplines' => $activity->getDisciplinesArray(),
             * 'motscles' => $activity->getMotsclesArray(),
             * 'members' => $members,
             * 'partners' => $partners,
             * 'project_id' => $project_id,
             * 'project' => $project_body,
             * /****/
            'mappings' => [
                'date_detection' => false,
                'numeric_detection' => false,
@@ -186,208 +175,18 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
        return $ids;
    }

    /**
     * Analyze the search pattern and return normalized search term with flags
     * @param string $search The search term
     * @return array{search: string, isExact: bool, isPrefix: bool}
     */
    private function analyzeSearchPattern(string $search): array
    {
        $isExact = false;
        $isPrefix = false;
        $normalizedSearch = $search;

        // Check for exact match (quoted text)
        if (strlen($search) >= 2 && str_starts_with($search, '"') && str_ends_with($search, '"')) {
            $isExact = true;
            $normalizedSearch = substr($search, 1, -1);
        }

        // Check for prefix search (ends with *)
        if (str_ends_with($normalizedSearch, '*')) {
            $isPrefix = true;
            $normalizedSearch = rtrim($normalizedSearch, '*');
        }

        return [
            'search' => $normalizedSearch,
            'isExact' => $isExact,
            'isPrefix' => $isPrefix
        ];
    }

    public function getFieldsSearchedWeighted(string $search): array
    {
        $analysis = $this->analyzeSearchPattern($search);
        $normalizedSearch = $analysis['search'];
        $isExact = $analysis['isExact'];
        $isPrefix = $analysis['isPrefix'];

        $query = ['bool' => [
            'should' => [],
            'minimum_should_match' => 1
        ]];

        ///////////////////////////////////////////// IDENTIFIANTS/KEYWORDS
        // N° Oscar
        if ($isExact) {
            $query['bool']['should'][] = ['term' => ['oscar' => [
                'value' => $normalizedSearch, 'boost' => 200]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['oscar' => [
                'value' => $normalizedSearch, 'boost' => 100]]];
        } else {
            $query['bool']['should'][] = ['term' => ['oscar' => [
                'value' => $normalizedSearch, 'boost' => 100]]];
//            $query['bool']['should'][] = ['prefix' => ['oscar' => [
//                'value' => $normalizedSearch, 'boost' => 30]]];
        }

        // N° financier (EOTP/PFI)
        if ($isExact) {
            $query['bool']['should'][] = ['term' => ['eotp' => [
                'value' => $normalizedSearch, 'boost' => 200]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['eotp' => [
                'value' => $normalizedSearch, 'boost' => 100]]];
        } else {
            $query['bool']['should'][] = ['term' => ['eotp' => [
                'value' => $normalizedSearch, 'boost' => 100]]];
//            $query['bool']['should'][] = ['prefix' => ['eotp' => [
//                'value' => $normalizedSearch, 'boost' => 30]]];
        }

        // Acronyme
        if ($isExact) {
            $query['bool']['should'][] = ['term' => ['acronym.keyword' => [
                'value' => $normalizedSearch, 'boost' => 160]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['acronym.keyword' => [
                'value' => $normalizedSearch, 'boost' => 100]]];
        } else {
            $query['bool']['should'][] = ['term' => ['acronym.keyword' => [
                'value' => $normalizedSearch, 'boost' => 80]]];
//            $query['bool']['should'][] = ['prefix' => ['acronym.keyword' => [
//                'value' => $normalizedSearch, 'boost' => 20]]];
            $query['bool']['should'][] = ['match' => ['acronym' => [
                'query' => $normalizedSearch, 'boost' => 10, 'fuzziness' => 10]]];
        }

        ///////////////////////////////////////////// TEXTES
        // Note doc :
        // 'match_phrase' : Terme exacte
        // 'prefix' : Commence par
        //  'match_bool_prefix' / 'match' : Recherche par défaut
        
        // Label
        if ($isExact) {
            $query['bool']['should'][] = ['match_phrase' => ['label' => [
                'query' => $normalizedSearch, 'boost' => 20]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['label' => [
                'value' => $normalizedSearch, 'boost' => 15]]];
        } else {
            $query['bool']['should'][] = ['match_bool_prefix' => ['label' => [
                'query' => $normalizedSearch, 'boost' => 6]]];
            $query['bool']['should'][] = ['match' => ['label' => [
                'query' => $normalizedSearch, 'boost' => 3, 'fuzziness' => 1]]];
        }

        // Project
        if ($isExact) {
            $query['bool']['should'][] = ['match_phrase' => ['project' => [
                'query' => $normalizedSearch, 'boost' => 10]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['project' => [
                'value' => $normalizedSearch, 'boost' => 8]]];
        } else {
            $query['bool']['should'][] = ['match' => ['project' => [
                'query' => $normalizedSearch, 'boost' => 2, 'fuzziness' => 'AUTO']]];
        }

        // Mots clés
        if ($isExact) {
            $query['bool']['should'][] = ['match_phrase' => ['motscles' => [
                'query' => $normalizedSearch, 'boost' => 10]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['motscles' => [
                'value' => $normalizedSearch, 'boost' => 8]]];
        } else {
            $query['bool']['should'][] = ['match' => ['motscles' => [
                'query' => $normalizedSearch, 'boost' => 2]]];
        }

        // Description
        if ($isExact) {
            $query['bool']['should'][] = ['match_phrase' => ['description' => [
                'query' => $normalizedSearch, 'boost' => 5]]];
        } elseif ($isPrefix) {
            $query['bool']['should'][] = ['prefix' => ['description' => [
                'value' => $normalizedSearch, 'boost' => 4]]];
        } else {
            $query['bool']['should'][] = ['match' => ['description' => [
                'query' => $normalizedSearch, 'boost' => 1]]];
        }

        // Numbers
        if ($isExact) {
            $query["bool"]["should"][] = ["term" => ["numbers" => [
                "value" => $normalizedSearch, "boost" => 20]]];
        } elseif ($isPrefix) {
            $query["bool"]["should"][] = ["prefix" => ["numbers" => [
                "value" => $normalizedSearch, "boost" => 15]]];
        } else {
            $query["bool"]["should"][] = ["match" => ["numbers" => [
                "query" => $normalizedSearch, "fuzziness" => 1, "boost" => 10]]];
        }

        // Disciplines
        if ($isExact) {
            $query["bool"]["should"][] = ["match_phrase" => ["disciplines" => [
                "query" => $normalizedSearch, "boost" => 10]]];
        } elseif ($isPrefix) {
            $query["bool"]["should"][] = ["prefix" => ["disciplines" => [
                "value" => $normalizedSearch, "boost" => 8]]];
        } else {
            $query["bool"]["should"][] = ["match" => ["disciplines" => [
                "query" => $normalizedSearch, "fuzziness" => 1, "boost" => 5]]];
        }

        // Activity type
        if ($isExact) {
            $query["bool"]["should"][] = ["term" => ["activitytype" => [
                "value" => $normalizedSearch, "boost" => 6]]];
        } elseif ($isPrefix) {
            $query["bool"]["should"][] = ["prefix" => ["activitytype" => [
                "value" => $normalizedSearch, "boost" => 5]]];
        } else {
            $query["bool"]["should"][] = ["match" => ["activitytype" => [
                "query" => $normalizedSearch, "fuzziness" => 1, "boost" => 3]]];
        }

        // Partners
        if ($isExact) {
            $query["bool"]["should"][] = ["match_phrase" => ["partners" => [
                "query" => $normalizedSearch, "boost" => 5]]];
        } elseif ($isPrefix) {
            $query["bool"]["should"][] = ["prefix" => ["partners" => [
                "value" => $normalizedSearch, "boost" => 4]]];
        } else {
            $query["bool"]["should"][] = ["match" => ["partners" => [
                "query" => $normalizedSearch, "fuzziness" => 1]]];
        }

        // Members
        if ($isExact) {
            $query["bool"]["should"][] = ["match_phrase" => ["members" => [
                "query" => $normalizedSearch, "boost" => 5]]];
        } elseif ($isPrefix) {
            $query["bool"]["should"][] = ["prefix" => ["members" => [
                "value" => $normalizedSearch, "boost" => 4]]];
        } else {
            $query["bool"]["should"][] = ["match" => ["members" => [
                "query" => $normalizedSearch, "fuzziness" => 1]]];
        }
        $query['bool']['should'][] = ['query_string' => [
            'fields' => ['oscar^100','eotp^100','acronym^50','label^5','numbers^25','motsclefs^25','description^2','project','numbers.keyword'],
            'query' => $search,
            'default_operator' => 'AND'
        ]];

        return $query;
    }