ecolabdata / ecospheres

Portail des données de la transition écologique et de la cohésion des territoires
https://ecologie.data.gouv.fr
2 stars 0 forks source link

Moissonnage DREAL ARA #184

Closed streino closed 1 month ago

streino commented 3 months ago

Plateforme de test pour la mise en place d'endpoints virtuels CSW sur Prodige/GN.

L'objectif est la création d'un endpoint avec filtre sur organisation pour remonter uniquement les données de la DREAL ARA présentes sur DatARA.

streino commented 3 months ago

Résultats des essais avec DatARA.

Prodige 4.4

Utilisation de la fonctionnalité de CSW virtuels au niveau Geonetwork. Nous n'arrivons pas à mettre en place un filtre sur l'organisation avec la config de base quelle que soit la requête Lucene formulée (exact match, tokens, etc.). Le filtre marche en ajoutant orgName dans la liste des champs tokenisés dans Lucene (le champ est le seul en commentaire dans la config par défaut). Prochaines étapes :

Prodige 5

Utilisation de la fonctionnalité de portails. Testé sur le Prodige 5 Ecolab. La requête renvoie une erreur :

POST https://catalogue-test.prodige-ecolab.fr/geonetwork/DREAL_ARA/fre/csw
Content-Type: application/xml

<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
                xmlns:gmd="http://www.isotc211.org/2005/gmd"
                service="CSW" version="2.0.2" resultType="results"
                startPosition="1" maxPosition="20"
                outputSchema="http://www.isotc211.org/2005/gmd">
  <csw:Query typeNames="csw:Record">
    <csw:ElementSetName>full</csw:ElementSetName>
  </csw:Query>
</csw:GetRecords>

<?xml version="1.0" encoding="UTF-8"?>
<ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2.0" xsi:schemaLocation="http://www.opengis.net/ows http://schemas.opengis.net/ows/1.0.0/owsExceptionReport.xsd">
  <ows:Exception exceptionCode="NoApplicableCode">
    <ows:ExceptionText>java.lang.RuntimeException: org.fao.geonet.csw.common.exceptions.InvalidParameterValueEx: code=InvalidParameterValue, locator=elementName has invalid XPath : , message=Invalid XPath expression: "/csw:Record//": Expected one of '.', '..', '@', '*', &lt;QName&gt;</ows:ExceptionText>
  </ows:Exception>
</ows:ExceptionReport>

La même requête sans ElementSetName fonctionne. Et la requête d'origine avec ElementSetName fonctionne sur https://catalogue.datara.gouv.fr/geonetwork/srv/fre/csw-dreal_opendata (Prodige 5 sans portail).

Le problème a été remonté à Prodige.

streino commented 2 months ago

Attention à désactiver le moissonnage Géocatalogue avant passage en prod du moissonneur DatARA direct. Cf https://github.com/ecolabdata/ecospheres/issues/55.

streino commented 2 months ago

Suite de l'investigation du problème de filtrage en Prodige 4.4 pour archive (j'ai fait quelques edits mineurs par rapport au mail original).

En attente de tests par Prodige de la solution proposée.

Comportement actuel

Le problème provient bien d'une incohérence entre indexation et search sur le champ orgName (c'est loin d'être le seul) :

Aucun de ces deux queries qui cherchent 3 tokens normalisés ne peut matcher le token stocké dans l'index.

=> Echec.

Solution

Cf Option 2.2 pour les détails.

Solution a minima sur orgName

Dans config-lucene.xml, ajouter :

<fieldSpecificAnalyzer>
  <Field name="orgName" analyzer="org.apache.lucene.analysis.core.KeywordAnalyzer"/>
</fieldSpecificAnalyzer>

Le filtre CSW matchera alors en mode "keyword" (exact match, absolument aucune transformation à l'indexation ou au search).

Donc il faudra spécifier dans le filtre le texte exact figurant dans gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName (= champs indexés dans orgName).

Par exemple :

orgName:"Direction Régionale de l’Environnement de l’Aménagement et du Logement d'Auvergne-Rhône-Alpes (DREAL Auvergne-Rhône-Alpes)"

(on notera que cet exemple pousse le vice jusqu'à utiliser deux types d'apostrophes... ce qui a une importance en exact match)

Solution alternative sur responsiblePartyEmail

On pourrait peut-être simplifier l'élaboration du filtre CSW en se basant sur le champ responsiblePartyEmail plutôt qu'orgName (si le champ est tjs renseigné dans les métadonnées ?).

D'un côté, un email est une sorte d'entité nommée, donc on peut espérer avoir moins de variations dans ce champ que dans orgName (ou alors on a un autre problème d'emails invalides...). De l'autre côté, "responsible party" semble mieux correspondre à ce qu'on veut filtrer, plutôt qu'orgName qui peut contenir les noms de plusieurs entités avec différents rôles.

Dans ce cas, dans config-lucene.xml, ajouter :

<fieldSpecificAnalyzer>
  <Field name="responsiblePartyEmail" analyzer="org.apache.lucene.analysis.core.KeywordAnalyzer"/>
</fieldSpecificAnalyzer>

Filtre correspondant :

responsiblePartyEmail:"ddt-geomatique@ain.gouv.fr"

Je n'ai pas testé cette piste au delà de vérifier qu'on remonte bien des résultats cohérents avec le filtre.

Détails techniques des options envisagées

Option 1 : Customiser l'indexation de orgName

Lors de nos précédents tests, nous avions activé la tokenization du champ orgName dans config-lucene.xml.

En conséquence, le champ orgName va être indexé avec l'analyzer custom GeoNetworkAnalyzer, qui fait globalement la même chose qu'un StandardAnalyzer. On va donc indexer 3 tokens : ddt, de, l'ain.

Les queries de filtre CSW orgName:(DDT de l'Ain) ou orgName:"DDT de l'Ain" vont matcher car on a bien les mêmes tokens dans l'index et le query.

En dehors de déterrer un changement vieux de 13 ans qui n'a par l'air d'avoir de rapport avec orgName, le véritable problème est qu'orgName n'est en fait pas configuré comme un champ de recherche, mais comme un champ de facettes. Donc si on change son type, on risque d'avoir des surprises au niveau des facettes (je ne me rappelle plus si Lucene s'en sort dans ce cas).

Ca pourrait expliquer le fait que le champ orgName ait été commenté dans la config (mais il aurait été préférrable de le supprimer).

=> Echec.

Option 2 : Customiser le filtrage sur orgName

Geonetwork utilise un PerFieldAnalyzerWrapper qui comme son nom l'indique permet d'avoir des Analyzers différents par champs. Le fichier config-lucene.xml contient les deux sections suivantes :

<!-- Field analyzer
  Define here specific analyzer for each fields stored in the index
  ...
-->
<fieldSpecificAnalyzer>
  <Field name="_uuid" analyzer="org.fao.geonet.kernel.search.GeoNetworkAnalyzer"/>
  ...
</fieldSpecificAnalyzer>

<fieldSpecificSearchAnalyzer>
  <!-- Define here analyzers to be overriden from fieldSpecificAnalyzer.
    By default, indexing and searching per field analyzers are the same.
  ...
</fieldSpecificSearchAnalyzer>

orgName ne se trouve dans aucune des deux sections par défaut puisque c'est un champ de facettes, et la construction de facettes se fait différement. En gros, le texte d'un champ facetté est stocké sans traitement en un seul token. Ca tombe bien, c'est aussi ce que fait le KeyworkAnalyzer.

Là où il y a un piège, c'est que le code qui parse les filtres CSW (la fonction parseLuceneQuery) utilise l'analyzer d'indexation et non celui de search.

Je ne sais pas si c'est un bug, mais ça nous arrange 😅

Option 2.1 : Customiser le filtrage sur orgName (côté search)

Si parseLuceneQuery utilisait l'analyzer de search (ce qui pourrait paraitre plus logique), nous devrions customiser fieldSpecificSearchAnalyzer pour utiliser un KeywordAnalyzer pour orgName.

Le filtre orgName:"DDT de l'Ain" serait alors parsé en orgName:DDT de l'Ain (ici "DDT de l'Ain" est un seul token), et on matcherait le keyword dans l'index.

Mais on changerait le comportement du search sur le champ orgName dans tout Geonetwork. Le search n'étant pas vraiment configuré sur orgName on peut imaginer que ça n'est pas trop grave, mais il est possible que ça affecte la sélection ou le drill-down par facettes, donc ça reste risqué.

Note par rapport au mail d'origine : Mon analyse est probablement incorrecte ou du moins incomplète. Mais comme cette approche n'est de toute façon pas une option, je laisse tel quel sans creuser.

=> Echec.

Option 2.2 : Customiser le filtrage sur orgName (côté index)

Par chance (?) parseLuceneQuery utilise l'analyzer d'indexation, donc il faut customiser fieldSpecificAnalyzer pour avoir un effet sur le filtre CSW.

Et comme orgName n'est pas un champ indexé pour la recherche mais un champ de facettes (qui n'utilise pas les analyzers d'indexation et indexe "à la façon" d'un KeywordAnalyzer), la déclaration explicite d'un analyzer d'indexation KeywordAnalyzer pour orgName (qui ne sera pas appelé) est un no-op au niveau de l'index final.

J'ai confirmé par :

Dans les deux cas le contenu de l'index pour le champ orgName est identique à celui avec la config d'origine.

Donc au niveau index :

Et au niveau search :

parseLuceneQuery est utilisé uniquement à deux endroits dans le code Geonetwork (filtres CSW et filtres Portails). Donc en plus on corrige le même bug au niveau des portails, si jamais on préférait utiliser des portails plutôt que des CSW virtuels 👌

Le risque d'effet de bord est donc limité aux filtres CSW ou portails filtrant sur orgName, ce qui me semble raisonnable.

=> Succès ?

Pour reproduire ou creuser encore plus

Côté search, passer le log Geonetwork à SEARCH depuis l'interface d'administration (section Paramètres > Serveur > Niveau de log).

Par exemple la transformation du filtre CSW en véritable query Lucene :

geonetwork-1  | 2024-04-04 19:27:28,291 INFO  [geonetwork.csw.search] - LuceneSearcher cswCustomFilter:
geonetwork-1  | +orgName:"DRAAF Rhône-Alpes"
geonetwork-1  | 2024-04-04 19:27:28,292 INFO  [geonetwork.csw.search] - LuceneSearcher cswCustomFilterQuery:
geonetwork-1  | orgName:"draaf rhone alpes"

Côté indexation, Geonetwork ne log pas grand chose, c'est dans Lucene que ça se passe.

On voit tout de même passer les documents juste avant l'indexation, ce qui permet de confirmer que le champ orgName contient bien l'info :

geonetwork-1  |     <Field name="orgName" string="DDT 69 (Direction Départementale des Territoires du Rhône)" store="true" index="true" />

Pour en voir plus il faut télécharger Luke et charger l'index Lucene de Geonetwork (attention à ce que la version de Luke corresponde à la version Lucene de Geonetwork).

On voit tout de suite la différence de contenu entre :

julien commented 2 months ago

@streino Aucune idée

streino commented 1 month ago

Autre problème rencontré sur DatARA -> https://github.com/geonetwork/core-geonetwork/issues/8020

streino commented 1 month ago

Benoist a validé les fixes ci-dessus sur un environnement de test Prodige 4.4 (autre que ARA). Il va voir avec Julien pour tester sur DatARA et si ok déployer en prod.

streino commented 1 month ago

Feu vert de Julien pour déployer sur DatARA 🥳

streino commented 1 month ago

Update :

En attente de validation par Julien mais tout a l'air OK.

streino commented 1 month ago

Fixes validés et moissonneur (re)mis en place par Julien sur https://demo.data.gouv.fr/fr/admin/harvester/66549feccb972ee8e5d76b93 :tada:

Vu avec Julien, on mettra en prod après #194.