Commit 3d72a3ad authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Travaux en cours sur le système de recherche textuel

parent b7bc086a
Loading
Loading
Loading
Loading
+114 −40
Original line number Diff line number Diff line
@@ -27,6 +27,57 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
        return $this->addItem($activity);
    }

    protected function indicesCreateBody(): array
    {
        return [
            'settings' => [
                'analysis' => [
                    'analyzer' => [
                        'folding_analyzer' => [
                            'tokenizer' => 'standard',
                            '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,
                'properties' => [
                    'id' => ['type' => 'keyword'],
                    'acronym' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'eotp' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'oscar' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'saic' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'numerotation' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'numbers' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],

                    'label' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                    'description' => [ 'type' => 'text', 'analyzer' => 'folding_analyzer'],
                ]
            ]
        ];
    }


    /**
     * @param mixed $object
     * @return array
@@ -36,8 +87,7 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
    {
        if (!$object instanceof Activity) {
            throw new OscarException("L'objet indexé doit être une activité");
        }
        else {
        } else {
            $activity = $object;
        }

@@ -150,44 +200,68 @@ class ElasticActivitySearch extends ElasticSearchEngine implements IActivitySear
            ]
        ];

        // TODO si plusieurs mots, ajouter une règle spécifique
        if ($wordsNbr > 1) {
            $query["bool"]["should"][] = [
                "query_string" => [
                    "query"  => $andQuery,
                    "fields" => [
                        'oscar^20',
                        'eotp^20',
                        'acronym^15',
                        'numbers^10',
                        'motscles^7',
                        'disciplines^7',
                        'label^5',
                        'project^5',
                        'activitytype^3',
                        'description^2',
                        'partners',
                        'members'
                    ]
                ]
            ];
        }
        else {
            $query["bool"]["should"] = [
                ["match" => ["oscar" => ["query" => $andQuery, "boost" => 20]]],
                ["match" => ["eotp" => ["query" => $andQuery, "boost" => 20]]],
                ["match" => ["acronym" => ["query" => $andQuery, "boost" => 15]]],
                ["match" => ["numbers" => ["query" => $andQuery, "boost" => 10]]],
                ["match" => ["motscles" => ["query" => $andQuery, "boost" => 7]]],
                ["match" => ["disciplines" => ["query" => $andQuery, "boost" => 7]]],
                ["match" => ["label" => ["query" => $andQuery, "boost" => 5]]],
                ["match" => ["activitytype" => ["query" => $andQuery, "boost" => 3]]],
                ["match" => ["project" => ["query" => $andQuery, "boost" => 5]]],
                ["match" => ["description" => ["query" => $andQuery, "boost" => 1]]],
                ["match" => ["partners" => ["query" => $andQuery, "boost" => 1]]],
                ["match" => ["members" => ["query" => $andQuery, "boost" => 1]]],
            ];
        }

////        // Champs Oscar
//        $query["bool"]["should"][] = [ "match" => [ "oscar" => [ "query" => $search, "boost" => 20 ]]];
//        $query["bool"]["should"][] = [ "prefix" => [ "oscar" => [ "value" => $search, "boost" => 5]]];
////
////        // Champ EOTP
//        $query["bool"]["should"][] = [ "match" => [ "eotp" => [ "query" => $search, "boost" => 20 ]]];
//        $query["bool"]["should"][] = [ "prefix" => [ "eotp" => [ "value" => $search, "boost" => 5]]];

//        // Champ ACRONYM
//        $query["bool"]["should"][] = [ "match" => [ "acronym" => [ "query" => $search, "fuzziness" => "auto", "boost" => 20 ]]];
//        $query["bool"]["should"][] = [ "prefix" => [ "acronym" => [ "value" => strtolower($search), "boost" => 5]]];

        // Champ LABEL/PROJECT LABEL
        $query["bool"]["should"][] = [ "match" => [ "label" => [ "query" => $search, "fuzziness" => "auto", "boost" => 4 ]]];
        $query["bool"]["should"][] = [ "match" => [ "project" => [ "query" => $search, "fuzziness" => "auto", "boost" => 3 ]]];

        // Champ NUMBERS
        $query["bool"]["should"][] = [ "match" => [ "numbers" => [ "query" => $search, "fuzziness" => "auto", "boost" => 5 ]]];





        /**
         * "query_string" => [
         * "query"  => $andQuery,
         * "fields" => [
         * 'oscar^20',
         * 'eotp^20',
         * 'acronym^15',
         * 'numbers^10',
         * 'motscles^7',
         * 'disciplines^7',
         * 'label^5',
         * 'project^5',
         * 'activitytype^3',
         * 'description^2',
         * 'partners',
         * 'members'
         * ]
         * ]
         * ];
         * var_dump($query); die();
         * }
         * else {
         * $query["bool"]["should"] = [
         * ["match" => ["oscar" => ["query" => $andQuery, "boost" => 20]]],
         * ["match" => ["eotp" => ["query" => $andQuery, "boost" => 20]]],
         * ["match" => ["acronym" => ["query" => $andQuery, "boost" => 15]]],
         * ["match" => ["numbers" => ["query" => $andQuery, "boost" => 10]]],
         * ["match" => ["motscles" => ["query" => $andQuery, "boost" => 7]]],
         * ["match" => ["disciplines" => ["query" => $andQuery, "boost" => 7]]],
         * ["match" => ["label" => ["query" => $andQuery, "boost" => 5]]],
         * ["match" => ["activitytype" => ["query" => $andQuery, "boost" => 3]]],
         * ["match" => ["project" => ["query" => $andQuery, "boost" => 5]]],
         * ["match" => ["description" => ["query" => $andQuery, "boost" => 1]]],
         * ["match" => ["partners" => ["query" => $andQuery, "boost" => 1]]],
         * ["match" => ["members" => ["query" => $andQuery, "boost" => 1]]],
         * ];
         * }
         * ****/

        return $query;
    }
+13 −19
Original line number Diff line number Diff line
@@ -57,27 +57,11 @@ abstract class ElasticSearchEngine
                    ->build();
            }
            if( !$this->elasticSearchClient->indices()->exists(['index' => $this->getIndex()]) ){
                $this->loggerService->debug("INDEX CREATE " . $this->getIndex());
                $this->loggerService->info("INDEX CREATE " . $this->getIndex());
                $this->elasticSearchClient->indices()->create(
                    [
                        'index' => $this->getIndex(),
                        'body' => [
                            'mappings' => [
                                // Suppression de la détection des dates/nombres
                                'date_detection' => false,
                                'numeric_detection' => false,
                                "dynamic_templates"=> [
                                  [
                                      "numerique_en_texte"=> [
                                      "match_mapping_type"=> "long",
                                      "mapping"=> [
                                          "type"=> "text"
                                      ]
                                    ]
                                  ]
                                ]
                            ]
                        ]
                        'body' => $this->indicesCreateBody()
                    ]
                );
            }
@@ -89,6 +73,16 @@ abstract class ElasticSearchEngine
        }
    }

    protected function indicesCreateBody(): array {
        return [
            'mappings' => [
                // Suppression de la détection des dates/nombres
                'date_detection' => false,
                'numeric_detection' => false
            ]
        ];
    }

    public function getMapping() :array {
        return $this->getClient()->indices()->getMapping(['index' => $this->getIndex()]);
    }
@@ -194,7 +188,7 @@ abstract class ElasticSearchEngine
            ]
        ];

        $this->loggerService->debug("----query elastic : \n" . json_encode($query['body']['query']) ."\n---- ");
        $this->loggerService->info("----query elastic : \n" . json_encode($query['body']['query']) ."\n---- ");

        return $query;
    }
+84 −10
Original line number Diff line number Diff line
@@ -38,6 +38,50 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
        return $this->addItem($person);
    }

    protected function indicesCreateBody(): array {
        return [
            'settings' => [
                'analysis' => [
                    'analyzer' => [
                        'folding_analyzer' => [
                            'tokenizer' => 'standard',
                            'filter' => ['lowercase', 'asciifolding']
                        ]
                    ]
                ]
            ],
            'mappings' => [
                'properties' => [
                    'id' => ['type' => 'keyword'],
                    'firstname' => [
                        'type' => 'text',
                        'analyzer' => 'folding_analyzer'
                    ],
                    'lastname' => [
                        'type' => 'text',
                        'analyzer' => 'folding_analyzer'
                    ],
                    'fullname' => [
                        'type' => 'text',
                        'analyzer' => 'folding_analyzer'
                    ],
                    'email' => [
                        'type' => 'text',
                        'analyzer' => 'folding_analyzer'
                    ],
                    'affectation' => ['type' => 'text'],
                    'location' => ['type' => 'text'],
                    'organizations' => ['type' => 'text'],
                    'activities' => ['type' => 'text'],
                    'connectors' => [
                        'type' => 'text',
                        'analyzer' => 'folding_analyzer'
                    ]
                ]
            ]
        ];
    }

    public function getIndexableDatas(mixed $item) :array
    {
        if( !$item instanceof Person ){
@@ -100,11 +144,12 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
        return [
            "bool" => [
                "should" => [
                    // ---- Fuzzy matches ----
                    [
                        "match" => [
                            "connectors" => [
                                "query" => $search,
                                "boost" => 6  // Favoriser les correspondances
                                "boost" => 6
                            ]
                        ]
                    ],
@@ -112,8 +157,8 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "lastname" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes
                                "boost" => 5  // Favoriser les correspondances
                                "fuzziness" => "AUTO",
                                "boost" => 5
                            ]
                        ]
                    ],
@@ -121,7 +166,7 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "fullname" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes,
                                "fuzziness" => "AUTO",
                                "boost" => 3
                            ]
                        ]
@@ -130,7 +175,7 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "firstname" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes,
                                "fuzziness" => "AUTO",
                                "boost" => 2
                            ]
                        ]
@@ -139,7 +184,7 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "email" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes,
                                "fuzziness" => "AUTO",
                                "boost" => 1
                            ]
                        ]
@@ -148,7 +193,7 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "location" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes,
                                "fuzziness" => "AUTO"
                            ]
                        ]
                    ],
@@ -156,18 +201,47 @@ class PersonElasticSearch extends ElasticSearchEngine implements IPersonISearchS
                        "match" => [
                            "affectation" => [
                                "query" => $search,
                                'fuzziness' => "AUTO", // "Tolérance" aux fautes,
                                "fuzziness" => "AUTO"
                            ]
                        ]
                    ],

                    // ---- Commence par (prefix) ----
                    [
                        "prefix" => [
                            "lastname" => $search,  // Documents qui commencent par l'expression
                            "lastname" => [
                                "value" => $search,
                                "boost" => 10
                            ]
                        ]
                    ],
                    [
                        "prefix" => [
                            "connectors" => $search,  // Documents qui commencent par l'expression
                            "connectors" => [
                                "value" => $search,
                                "boost" => 8
                            ]
                        ]
                    ],

                    // ---- Autocomplétion et Prénom + Nom ----
                    [
                        "match_phrase_prefix" => [
                            "fullname" => [
                                "query" => $search,
                                "slop" => 2,              // tolère inversion prénom/nom
                                "max_expansions" => 20,
                                "boost" => 12
                            ]
                        ]
                    ],
                    [
                        "multi_match" => [
                            "query"  => $search,
                            "type"   => "cross_fields",
                            "fields" => ["firstname^2", "lastname^3"],
                            "operator" => "and",
                            "boost" => 9
                        ]
                    ]
                ],