Commit 95f78d66 authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Patch recherche activités

parent 5c37e8ce
Loading
Loading
Loading
Loading
Loading
+228 −69
Original line number Diff line number Diff line
@@ -64,8 +64,8 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
                'properties' => [
                    'id' => ['type' => 'keyword'],
                    'acronym' => ['type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'eotp' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'oscar' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'eotp' => ['type' => 'keyword' ],
                    'oscar' => ['type' => 'keyword'],
                    'saic' => ['type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'numerotation' => ['type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'numbers' => ['type' => 'text', 'analyzer' => 'folding_analyzer'],
@@ -132,16 +132,45 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear

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

        // Build query based on pattern
        if ($isExact) {
            // Exact match - use match_phrase for project field
            $query = [
                'match_phrase' => [
                    'project' => [
                        'query' => $normalizedSearch
                    ]
                ]
            ];
        } elseif ($isPrefix) {
            // Prefix search - use prefix query
            $query = [
                'prefix' => [
                    'project' => [
                        'value' => $normalizedSearch
                    ]
                ]
            ];
        } else {
            // Default - use query_string with OR for prefix matching
            $query = [
                'query_string' => [
                    'query' => sprintf('%s OR %s*', $normalizedSearch, $normalizedSearch)
                ]
            ];
        }

        $params = [
            'index' => $this->getIndex(),
            'type' => $this->getType(),
            'body' => [
                'size' => 10000,
                'query' => [
                    'query_string' => [
                        'query' => sprintf('%s OR %s*', $what, $what)
                    ]
                ]
                'query' => $query
            ]
        ];

@@ -157,78 +186,208 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
        return $ids;
    }

    public function getFieldsSearchedWeighted(string $search): array
    /**
     * 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
    {
        $andQuery = null;
        $wordsNbr = 1;

        // Détection des recherches strictes
        if (preg_match_all('/^"(.*)"$/', $search, $matches, PREG_SET_ORDER)) {
            if (count($matches) == 1 && array_key_exists(1, $matches[0])) {
                $andQuery = $matches[0][0];
                $wordsNbr = 2;
        $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);
        }
        }

//        if(preg_match_all('/^query:(.*)$/', $search, $matches, PREG_SET_ORDER)) {
//            if( count($matches) == 1 && array_key_exists(1, $matches[0])) {
//                $andQuery = $matches[0][1];
//                $wordsNbr = 2;
//            }
//        }

        if (preg_match_all('/^(.*)\*$/', $search, $matches, PREG_SET_ORDER)) {
            if (count($matches) == 1 && array_key_exists(1, $matches[0])) {
                $andQuery = $matches[0][0];
                $wordsNbr = 2;
            }
        // Check for prefix search (ends with *)
        if (str_ends_with($normalizedSearch, '*')) {
            $isPrefix = true;
            $normalizedSearch = rtrim($normalizedSearch, '*');
        }

        if ($andQuery === null) {
            $words = explode(" ", $search);
            $wordsNbr = count($words);
            $andQuery = implode(" AND ", $words);
        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]]];
        }

        $query = [
            "bool" => [
                "should" => [
        // 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]]];
        }

                ],
                "minimum_should_match" => 1
            ]
        ];
        // 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]]];
        }

        // Champs Oscar
        $query["bool"]["should"][] = [ "match" => [ "oscar" => [ "query" => $search, "boost" => 20 ]]];
        $query["bool"]["should"][] = [ "prefix" => [ "oscar" => [ "value" => $search, "boost" => 5]]];
        ///////////////////////////////////////////// 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]]];
        }

        // Champ EOTP
        $query["bool"]["should"][] = [ "match" => [ "eotp" => [ "query" => $search, "boost" => 20 ]]];
        $query["bool"]["should"][] = [ "prefix" => [ "eotp" => [ "value" => $search, "boost" => 5]]];
        // 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']]];
        }

        // Champ ACRONYM
        $query["bool"]["should"][] = [ "match" => [ "acronym" => [ "query" => $search, "fuzziness" => 1, "boost" => 20 ]]];
        $query["bool"]["should"][] = [ "prefix" => [ "acronym" => [ "value" => strtolower($search), "boost" => 5]]];
        // 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]]];
        }

        // Champ LABEL/PROJECT LABEL
        $query["bool"]["should"][] = [ "match" => [ "label" => [ "query" => $search, "fuzziness" => 1, "boost" => 4 ]]];
        $query["bool"]["should"][] = [ "match" => [ "project" => [ "query" => $search, "fuzziness" => 1, "boost" => 3 ]]];
        // 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]]];
        }

        // Champ NUMBERS
        $query["bool"]["should"][] = [ "match" => [ "numbers" => [ "query" => $search, "fuzziness" => 1, "boost" => 5 ]]];
        // 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]]];
        }

        // Champ MOTSCLES
        $query["bool"]["should"][] = [ "match" => [ "motscles" => [ "query" => $search, "fuzziness" => 1, "boost" => 5 ]]];
        $query["bool"]["should"][] = [ "match" => [ "disciplines" => [ "query" => $search, "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]]];
        }

        $query["bool"]["should"][] = [ "match" => [ "activitytype" => [ "query" => $search, "fuzziness" => 1, "boost" => 3 ]]];
        $query["bool"]["should"][] = [ "match" => [ "description" => [ "query" => $search, "fuzziness" => 1, "boost" => 2 ]]];
        $query["bool"]["should"][] = [ "match" => [ "partners" => [ "query" => $search, "fuzziness" => 1]]];
        $query["bool"]["should"][] = [ "match" => [ "members" => [ "query" => $search, "fuzziness" => 1]]];
        // 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]]];
        }

        return $query;
    }