Intégration XML à DB2.


OmniFind V1R2


Le serveur OmniFind est fourni avec la version 7 de IBM i. Il permet une indexation des champs texte, texte enrichi (format .doc ou .pdf, par exemple) et enfin, avec cette nouvelle version 1.2, les champs de type XML.

 

OmniFind apporte :

 

Ce produit s'installe par RSTLICPGM 5733OMF, les options 30,33 et 39 de SS1 et java (JV1) sont des pré-requis.


L'installation doit vous créer un serveur de texte avec l'ID n° 1 (cela créé un répertoire /QOpenSys/QIBM/ProdData/TextSearch/server1)

La requête suivante donne la liste des serveurs :
   SELECT SERVERID,SERVERPORT,SERVERSTATUS,SERVERPATH FROM QSYS2.SYSTEXTSERVERS
   (ServerStatus à 0 indique un serveur actif, 1 inactif)

Ainsi que System i navigator

 

le serveur se démarre avec cette même interface ou IBM Navigator Director




ou avec les procédures cataloguées suivantes

 

Indexation

Vous pouvez créer un index OmniFind sur les types de donnée suivants :

les données peuvent être stockées en texte simple, HTML, XML, ou un format enrichi. Elles seront transformées en UNICODE 1208 avant d'être indexées, donc pas de job en CCSID(65535).Ce ne sont pas des index traditionnels DB2 (pas d'objet, donc pas de SAVOBJ) , ils ne sont pas maintenus temps réel et n'ont d'existence que dans le cadre du serveur OmniFind.


Les index sont enregistrés dans SYSTXTINDX de QSYS2, trois triggers sont ajoutés à la table indexée qui stockent les mises à jour dans une table temporaire, dite table de transfert, crée elle aussi à cette occasion (toujours dans QSYS2).

Création d'un Index


CALL SYPROCS.SYSTS_CREATE

Paramètres

(les valeurs par défaut des options sont stockées dans SYSTEXTDEFAULTS)

Exemple :

CALL SYSPROC.SYSTS_CREATE('BDVIN1', 'PRODUCTEURS_IX',  'BDVIN1.PRODUCTEURS(PR_AVIS)', 
 'CCSID 1208 LANGUAGE fr_FR FORMAT TEXT UPDATE FREQUENCY NONE UPDATE MINIMUM 1 INDEX CONFIGURATION(IGNOREEMPTYDOCS 1 , UPDATEAUTOCOMMIT 100)');


Une ligne est ajoutée dans SYSTEXTINDEXES (Nom système : SYSTXTINDX)

la table de transfert est créé dans QSYS2 (son nom est précisé dans STAGINGTABLENAME), les trois triggers sont ajoutés à la table indexée afin d'écrire dans la table de transfert

un répertoire est créé dans l'IFS (répertoire /QOpenSys/QIBM/ProdData/TextSearch/server1/config/collections)
son nom est indiqué par COLLECTIONNAME (par exemple 0_1_3_2010_09_28_17_10_36_131543, pour l'index 3 créé en septembre 2010)

Une vue est créé portant le nom de l'index (PRODUCTEURS_IX) dans la bibliothèque indiquée. C'est le seul objet pouvant être sauvegardé par SAVOBJ.SAVLIB.
  La restauration de la vue, recréé l'index de recherche OmniFind (sans les données) et relance l'indexation.

 

Ensuite, il vous lancer la procédure de mise à jour (l'index est créé vide par SYSTS_CREATE) :

CALL SYPROCS.SYSTS_UPDATE


l'index est alors créé dans le répertoire de la collection (la création prend au moins 3 à 5 fois le temps de création d'un index "normal")

 


-> Pour détruire l'index


CALL SYPROCS.SYSTS_DROP

 

-> Pour modifier les caractéristiques de l'index


CALL SYPROCS.SYSTS_ALTER

 

Recherche

Deux fonctions sont à votre disposition :

Exemple :

SELECT * FROM bdvin1.producteurs 
WHERE contains(pr_avis,'excellent') = 1

 

Que mettre dans une expression de type texte

Exemple :

select pr_avis FROM bdvin1/producteurs WHERE               
contains(pr_avis, 'chateau AND (pomerol OR lafite)') = 1 ;


trouve les lignes contenant chateau ou château ou châteaux puis, soit pomerol, soit lafite.

 

On peut même créer un dictionnaire de synonymes personnel en créant un fichier XML

Exemple :

<?xml version="1.0" encoding="UTF-8"?>
<synonymgroups version="1.0">
<synonymgroup>
<synonym>vin</synonym>
<synonym>pinard</synonym>
<synonym>picrate</synonym>
<synonym>nectar</synonym>
</synonymgroup>
<synonymgroup>
<synonym>syrah</synonym>
<synonym>schiraz</synonym>
</synonymgroup>

</synonymgroups>

puis en passant la commande (sous QSH)

synonymTool.sh importSynonym
-synonymFile <chemin du fichier XML>
-collectionName <nom de la collection>
-replace <[true|false]>
-configPath <chemin absolu du dossier de config.>
Exemple > synonymTool.sh importSynonym
-synonymFile /temp/vin_synonyme.xml
-collectionName 0_1_3_2010_09_28_17_10_36_131543 -replace false
-configPath /QopenSys/QIBM/ProdData/TextSearch/server1/config

IQQD0084I The request was successfully executed.
$

 

select count(*) FROM bdvin1/producteurs WHERE
contains(pr_avis, 'pinard')= 1 Donne 1 (pinard est le nom d'un producteur de Cognac) select count(*) FROM bdvin1/producteurs WHERE
contains(pr_avis, 'pinard', 'SYNONYM=ON')= 1 Donne 606

 

Recherche XML

La syntaxe des recherches XML utilise un sous-ensemble du langage W3 XPath

sous la forme CONTAINS(nom_colonne, '@xmlxp: ' 'expression_requête_Xpath' '   ')
le deuxième paramètre de la fonction CONTAINS est une chaîne donc entre quote ('), l'expression XPath étant elle même entre quotes il faut doubler ces dernières

vous devez indiquer un chemin dans l'arborescence XML :

Expression XPath Signifie
/ sélectionne le nœud, dit root element, qui englobe tout le document sauf <?xml version="1.0"?>
// sélectionne tous les noeuds
. sélectionne le nœud en cours
/customerinfo sélectionne le nœud "customerinfo"
//city sélectionne tous les éléments "city" du document où qu'ils soient
/customerinfo/name sélectionne l'unique élément "name" fils de "customerinfo"

puis, éventuellement, un Predicat (un test) devant être vrai, toujours entre crochets [ et ]

Prédicat Signifie
//phone[. = "xxx"] sélectionne tous les éléments "phone" du document (où qu'ils soient), ayant une valeur égale à xxx
//phone[@type = "work"] sélectionne tous les éléments "phone" du document, ayant un attribut "type" dont la valeur est "work"

Pour les valeurs :

Exemples :

INSERT INTO Customer (Cid, Info) VALUES (1000,        
'<customerinfo xmlns="http://posample.org" Cid="1000">
<name>Kathy Smith</name>
<addr country="Canada">
<street>5 Rosewood</street>
<city>Toronto</city>
<prov-state>Ontario</prov-state>
<pcode-zip>M6W 1E6</pcode-zip>
</addr>
<phone type="work">416-555-1358</phone>
</customerinfo>') INSERT INTO Customer (Cid, Info) VALUES (1002,
'<customerinfo xmlns="http://posample.org" Cid="1002">
<name>Jim Noodle</name>
<addr country="Canada">
<street>25 EastCreek</street>
<city>Markham</city>
<prov-state>Ontario</prov-state>
<pcode-zip>N9C 3T6</pcode-zip>
</addr>
<phone type="work">905-555-7258</phone>
</customerinfo>') INSERT INTO Customer (Cid, Info) VALUES (1003,
'<customerinfo xmlns="http://posample.org" Cid="1003">
<name>Robert Shoemaker</name>
<addr country="Canada">
<street>1596 Baseline</street>
<city>Aurora</city>
<prov-state>Ontario</prov-state>
<pcode-zip>N8X 7F8</pcode-zip>
</addr>
<phone type="work">905-555-2937</phone>
</customerinfo>')

 

-- liste des clients possédant un noeud "name" dans la zone XML INFO
SELECT * from posample/customer
where contains(info, '@xmlxp:''//name'' ') = 1 ....1....+.
CID
1.000 1.002 1.003


-- liste des clients possédant un noeud "phone" = à 416-555-1358
SELECT * from posample/customer
where contains(info, '@xmlxp:''//phone[. = "416-555-1358"]'' ')=1

....1....+.
CID
1.000


-- liste des clients possédant un noeud "phone" contenant 905
SELECT * from posample/customer
where contains(info,'@xmlxp:''//phone[. contains("905") ]'' ') = 1 ....1....+.
CID
1.002
1.003

 

-- liste des clients possédant le nœud "phone" de customerinfo = 416-555-1358
SELECT * from posample/customer
where contains(info,'@xmlxp:''/customerinfo[phone = "416-555-1358"]'' ')=1

....1....+.
CID
1.000

La PTF SI40272 ainsi que le dernier niveau de GROUP PTF pour DB2 (level 9) apporte à Omnifind, deux fonctions supplémentaires

 

Vous devez d'abord créer une collection pour stocker ces informations, cela va créer une bibliothèque, contenant

Ensuite vous devez accorder des droits à la procédure cataloguée SEARCH qui vient d'être créé

SET CURRENT SCHEMA OMNI_COL

GRANT EXECUTE ON PROCEDURE SEARCH(VARCHAR) TO QPGMR

 

comment ajouter des objets à l'index, toujours par procédure cataloguée

IL faut toujours commencer par définir la collection dans le chemin de recherche des procédures cataloguées

SET CURRENT PATH OMNI_COL

Ensuite vous devez rafraîchir l'index OmniFInd pour indexer réellement

CALL UPDATE

 

enfin vous pouvez faire des recherches, par CALL SEARCH('mot-recherché')

cela retourne un "result set" structuré comme suit :

Exemple

structure de la zone OBJECTINFOR

Autres procédures

QUERY_OBJECT_SET
   Retourne la liste des objets indexés

GET_OBJECT_STATUS
  retourne le status d'un objet

GET_OBJECTS_NOT_INDEXED
  retourne la liste des objets non indexés

STATUS
  retourne le status du serveur

SYSTS_DRPCOL
  détruit une collection

Pour de plus amples détails, voyez la documentation http://www-03.ibm.com/systems/resources/systems_power_ibmi_omnifind_extensions_user_guide.pdf