vendredi 24 août 2012

Clarification sur le Datawarehousing


Depuis quelques temps déjà on nous parle de plus en plus de datawarehouse (c'est un assez vieux concept qui semble revenir à la mode) et d’un terme que je trouve un peu pompeux le BI. Etant obligé par mon travail à replonger dans cet univers (mauvais jeu de mot ?), voici un petit billet concernant quelques cogitations à ce sujet…

OLTP et OLAP

OLTP : online transaction process : il s’agit là des base de données bien connu et bien classique (RDMS, entendez relational database management system). Le but de ces bases de données est de stocker des données utilisateurs via des applications clientes. Les paramètres importants sont :
1        1)Transactionnel (toujours se retrouver dans un état cohérent, même si le système crash)
2          2)Intégrité de donnée (clé primaire, foreign key, contrainte)
3          3)Index
4          4)Gestion d’accès concurrent (cfr transaction : Atomicity, Consistency, Isolation, Durability)
L’accent est mis sur la rapidité d’accès aux données et l’intégrité de celle-ci. Idéalement, de mon point de vue, une base de donnée OLTP ne devrait même pas être utilisée pour du reporting (sauf reporting bête et méchant).  Un chirurgien doit attendre d’opérer un patient, car il ne peut accéder aux informations du patient parce que le système est bloqué par quelqu’un générant un rapport trop lourd. Ces types de situations sont évidemment inacceptables.
Pour optimiser et réduire la redondance des informations, on utilise abusivement des formes normales.
Dans certains cas on utilise des ORM (iBATIS, Hibernate…) pour construire la structure du RDMS et assurer un mapping cohérent entre l’architecture objet et sa persistance transactionnelle.

OLAP : online analytical process
Ces bases de données sont dédiées au reporting, voir au reporting sur plusieurs dimensions. Dans cec cas de figure aucun souci par rapport au performance, puisque les deux bases de données sont séparées physiquement.
La structure des tables n’a plus rien à voir avec une base de donnée classique puisque la plupart des tables sont dé-normalisées. L’accès en écriture se fait en général via un processus d’ETL (Export, Transform, Load).
Pratiquement on utilise une table de fait représentant des comptes  en fonction de différentes dimensions. (Axe d’analyse), il s’agit de la table centrale. Les  dimensions sont des variables catégorielles independantes. L’ensemble des dimension forment un espace appelé Univers. La table centrale contient une foreign key pour chaque dimension (on appelle cette modélisation, modélisation en étoile, c’est une des plus simples). On peut aussi décomposer les dimensions suivant leur hiérarchies et définir des sous tables par dimension et niveau hiérarchique (architecture en flocon de neige). On peut aussi faire un mix des deux…
D’un point de vue pratique, même si des clés primaires peuvent être définies conceptuellement, aucune contrainte n’est mise sur la DB et l’autocommit est aussi désactivé puisque la DB fonctionne en read only.
Une fois les dimensions clairement établies, celles-ci peuvent être lues via certains outils de BI (Pentaho, offre quelque bon exemple open source, ceci dit il est aussi possible de faire du BI avec Excel).
Avant de se lancer dans la conception du système, il est important de se figurer les rapports dont on a besoin et les axes suivant lesquels on voudrait naviguer dans les données. Il faut veiller que ses axes soient indépendants (ou alors les regrouper sous forme hiérarchique). On définit ensuite la hiérarchie, puis on modélise.
La partie tricky à mon sens est la partie ETL car si quelque chose foire là-dedans, cela peut très vite devenir problématique. D’une part, les données peuvent venir d’une foulée de systèmes différents, donc on a besoin de réconciliation et de consolidation (remettre les bons ID), d’autre part si la réconciliation se passe mal, ce sont tous les résultats qui peuvent être impacté. C’est pourquoi il est important d’une part de travailler dans une sandbox, et d’autre part de bien dater les modifications.
Une fois les données prêtes (dans mon cas via des scripts PERL), il faut ensuite faire un bulk-copy dans la base de donnée OLAP. Comme cette DB est read-only, la seule phase d’écriture se fait au moment du chargement (LOAD), en général on utilise un bulk-copy (bcp) ou COPY en Postgres.
Les bases de données OLAP sont souvent qualifiées de Datawarehouse, en général le domaine qui nous occupe s’appelle un datamart (partie d’un datawarehouse), si le domaine concerné impacte le business par rapport à ses ventes on parle alors de BI (Business intelligence). Dans ce cas les dimensions sont souvents:la géographie (Région/Pays/Ville), le temps(Year/Quarter/Month), les types de produits. La table de fait est en général le total des ventes en fonctions des dimensions précitées.
Plusieurs systèmes peuvent être utilisés pour créer une base de donnée OLAP : SAS, SQL-Server, ORACLE ou dans les gratuits : R et PostgreSQL. Il en existe bien sûr d’autres mais ce sont ceuxt là que je connais le mieux…

mardi 26 juin 2012

Exercice 1.C


référence :
http://static.springsource.org/spring-ws/sites/1.5/reference/html/tutorial.html

Web Service :
Contract Last : on écrit d'abord le code Java et sur base de cela on génère le contrat après (WSDL)
Contract First : On écrit d'abord le contrat (WSDL) et on génère du Java à partir de là.

Rappel sur les dates :
ISO 8601 format : yyyy-mm-dd

D'une manière générale le XSD deviendra le Data Contract (qui définira le payload) :
Voir le rappel sur les XSD et le XSD final généré :

Une fois le data contract terminé on passe au Service Contract : Le WSDL
En général Spring WS sait générer le WSDL pour nous automatiquement

WSDL abstract parts : (doc xml utilisé pour localiser et décrire des webservices)
  1. definitions :<definitions>
    - namespaces
    - types <wsdl:types><xsd:schema xmlns>
    data type definition : décrits les types des paramètres impliqués dans le message
    </xsd:schema></wsdl:types>
  2. on définit le message : <wdsl:message>
    xsd décrivant la forme du message (data contract). Un peu comme les paramètres d'une fonction
    </wsdl:message>
  3. On décrit un porttype :
    <portType>
    décrit les opérations et les message impliqués
    </portType>
  4. Binding : on associe le message à un port type comme opération (le porttype sera utilisé dans le binding)
    <binding>
    protocoles et format de données
    </binding>
    </definitions>

Exemple : portType
<message name= »getTermRequest »>
<part name= »term » type= »xs:string » />
</message>
<portType name= »gloassaryTerms » />
<operation name= »getTerm »>
<input message= »getTermRequest » />
<output message= »getTermResponse » />
</operation>
</portType>
Dans ce cas de figure glossaryTerms peut être comparé à une librairie de fonction (ou classe?)
En gros le portType se comporte comme une classe accessible via le web.
Request-response est le mode de fonctionnement le plus commun.
Les autres types sont:
  • One-way : pas de réponse attendue (uniquement input est défini
  • Request-response : web request classique (stateless) : input / output
  • Solicit-response : l'appli va attendre la réponse (statefull?)
  • Notification : le serveur envoie un message mais n'attend pas de réponse

Le binding :
deux attributs :
  • name : nom du binding
  • type : pointe sur le port (une instance de porttype)

Le binding contient l'élément : soap:binding (style et transport)
  • style : rpc/document
  • transport : HTTP (mais pourrait-être autre chose : JMS)
Rmk on ne définit pas transport comme étant HTTP mais :

Le soapbinding contient l'élément opération :
définir l'opération que le portType expose
c'est là que l'on définit les requêtes http qui permettrond l'appel ex :
Il faut aussi spécifier les types d'entrées sortie : ex:literal


WSDL concrete part
on effectue un
  • binding qui indique au client comment invoker l'opération
  • service qui dit au client où la trouver (le binding sera utilise dans le port du service)

Voir le tutoriel pour explications complémentaires :

On crée le projet via Maven2
mvn archetype:create -DarchetypeGroupId=org.springframework.ws -DarchetypeArtifactID=spring-ws-archetype -DarchetypeVersion=1.5.9 -DgroupId=be.sdlg.ws -DartifactId=anovaWS

On obtien un répertoire src/main/webapp
Le servlet spring-ws est automatiquement crée et les requêtes redirigés vers lui.

3.6 Implementing the endpoint
Remarque sur les documents XML

Mieux vaut utiliser un name space lorsque l'on déclare un élément :
<ELEMENT xmlns= « http://www.sdlg.be/web/myapp/schemas »>
</ELEMENT>

Utliser plutôt
AnovaRequest (éviter les – car conversion vers Java class)

Web services en Spring WS 3


Spring WS repose JAX-WS car X-Fire et JAX RPC sont devenus obsoletes

Utiliser Spring service exporter (Web Service Last Contract) : Spring va construire le WSDL après que le service ai été défini.

Construire un Web service last contract avec Spring 3

Il faut utiliser le bean SimpleJaxWsServiceExporter

@WebService (serviceName="AnnovaService")
public class AnovaServiceEndPoint extends SpringBeanAutowiringSupport {

@Autowired
AnovaService anovaService;

@WebMethod
public AnovaTable getAnova(List response, List regressor ) {
return anovaService.getAnova(response, regressor);
}
}

Dans le fichier sybil-servlet.xml

<bean class="org.springframework.remonting.jaxws.SimpleJaxWsExporter" p:baseAddress="http://localhost:8888/service/" / >

Ce bean publie automatiquement les pojo contenant l'annotation @WebService
l'adresse de base est /localhost:8080/AnovaService

Consommation de web service par les clients:
ProxyBeanFactory => crée un objet client à partir du WSDL
(La partie message du WSDL décrit les types de données, les types complexes sont défnis via des types xsd: simples)
(Le portType décrit les différentes opérations supportées)
=> Le proxy bean crée par le ProxyBeanFactory va simplement invoker les méthodes sur le serveur distant, comme les types de données sont connus, il est tout à fait possible pour le ProxyBean de recréer les classes correspondantes...

Toutefois, si l'on définit un classe de type AnovaTable, il serait tout de même bon d'avoir sa définition complète côté client pour pouvoir utiliser ce type de données ailleurs dans l'appli...

Là il est possible d'utiliser JDom ou mieux JAXB pour populer ces classes.

Sécuriser les accès au Web service: 

utiliser JaaS (Java authentication & authorization Service) : (à mettre à jour)

vendredi 22 juin 2012

Rappels sur XSD

Dans le cadre de la partie C ( Exposer un Web Service qui renvoit une table ANOVA) de l'exercice précédent proposé, il est peut-être bon de faire un petit rappel sur les schémas XML:


Rappel de XML (Extended Markup Language):
XML                    Base de données       Programmation Orienté Objet
Xml Schema          Table Structure Class
Xml Document      Table Data         Instance (Object)

Un schéma ou fichier .xsd permet de définir la structure du contenu d'un document XML. Il existe différentes approches: DTD (Document Type definition), XSD,  XDR 
DTD:  compliqué et pas basé sur XML
XDR:  propriété de Microsoft (on oublie)
XSD : relativement répandu et sera notre choix:
caractéristiques:
- xml based
- support inheritance
- ability to define its own type (Complex-type)
- specify data types for element & attributes

1) Schema : Pour pouvoir utiliser un document pour valider d'autre document il faut qu'il soit lui même validé !


<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
</xsd:schema>


Notre document devra donc suivre la structure et les types décrits dans www.w3.org/2001/XMLSchema

2) Element: spécifie le type d'informations
argument :
@name : nom de l'info ex: name="RESPONSE"
@type : refère à un type simple ou complexe
@minoccurs : par défaut 0 mais peut forcer 1 ou n occurrence de l'élément pour que le doc xml soit valide
@maxoccurs : nombre d'occurence max, pour dire que c'est indéfini ou utilise maxoccurs="unbound"
@ref : allows to refer an element defined in an othr xsd don't forget

3) Complex Type
ATTENTION les simpleType ou complexType peuvent être globaux ou locaux.

Element containing other child elements or attributes


spécifie l'ordre dans lequel doivent se suivrent les éléments apparaissant dans le doc XML. Si l'ordre n'est pas respecté le validateur va gueuler.




<xsd:sequence>
</xsd:sequence>
spécifie l'ordre dans lequel doivent se suivrent les éléments apparaissant dans le doc XML. Si l'ordre n'est pas respecté le validateur va gueuler.

<xsd:complexType>
<xsd:extension base="xsd:Employee"> <!-- permet de faire un véritable héritage d'élement -->
</xsd:complexType>


4) Simple Type
User Defined type: crée à partir d'un type de base:
Principaux types de base (primitve types) supporté par XSD
- xsd:string
- xsd:int
- xsd:date
- xsd:datetime
- xsd:boolean
- xsd:float
- xsd:double

Il est possible de créer un "simple type" sur base d'un type primitif et de lui ajouter des restrictions (ex: valeur interdites via une regexp)

<xsd:simpleType name="ssnumber"> <xsd:restriction base="xsd:string"> <!-- hérite de xsd:string--> <xsd:length value="11" /> <xsd:pattern value="\d{3}\-\d{2}-\d{4} /< <!-- securité sociale --> </xsd:restriction> </xsd:simpleType>ou

<xsd:simpleType name="emp-type"< >xsd:restriction base="xsd:string"> <!-- hérite de xsd:string--< <xsd:enumeration value = "fulltime"/> <xsd:enumeration value = "parttime"/> </xsd:restriction> </xsd:simpleType> En XSD on appelle les différentes restrictions: "enumeration, length, pattern" sur un type de base, des "Facets"

5) Documenter un schéma:

<xsd:annotation> <xsd:documentation> <!-- donne des infos sur les fonctionalités pour lesquelles les éléments sont définis --> &lt/xsd:documentation> <xsd:appInfo> <!-- donne des infos sur l'application qui utilise les éléments--> </xsd:appInfo> </xsd:annotation>

Voilà à la prochaine apparition nous verrons comment:
- valider un document XML par rapport à son xsd
- concevoir directement des classes java à partir d'un xsd

jeudi 31 mai 2012

Exercice de statistiques combinant Spring3.1, R et ExtJS 4.

Exercice de statistiques combinant Spring3.1, R et ExtJS 4.

- Créer une DB simple avec 4 tables:
- Sujet
- ItemGroup
- Variables
- Instances

Créer 3 variables qui représente les résultats d'un test de mesure d'une appli web dans différents environnements:

- Temps de réponse [s]
- Environnement {A = Server 2003 + Sql Server 2005 + App V1,
B = Server 2008 + Sql Server 2008 + App V2,
C = Server 2008 + Sql Server 2008 + App V1}
- Concurrent users : [#]

Ces variables peuvent être chargées manuellement dans la DB.

A) Créer une application ExtJS 4 MVC
A.1) Stocker ces variables au format json
A.2) Afficher une grid permettant d'éditer (CRUD) les résultats pour les différentes variables par sujet. Les sujets ici, étant les tests effectués.
A.3) Afficher un écran permettant de sélectionner les variables à analyser au moyen de drag & drop.

B) Implémenter les fonctionalités CRUD pour connecter la grid ExtJS à la base de donnée en utilisant Spring MVC REST.
B.1)  Utiliser Hibernate pour connecter le modèle (Sujet, ItemGroup, Variables, Instances) à la DB.
B.2)  Utiliser JBoss comme server d'application
B.4) implémenter une fonctionalité d'analyse ANCOVA dans un service en utilisant R.
B.5) Sortir les résultats de l'analyse dans une page web en appelant le service
B.6) sortir les graphes de diagnostic (toujours au moyen du service) :
- normalité des résidus
- leverage (ou distance de Cook)

C) Créer et exposer un WS Service utilisant le service développé pour MVC
Utiliser JRI & R

samedi 31 mars 2012

Un peu de REST

Ce billet est une très brève introduction à la technologie REST et sera complété ultérieurement.

Depuis plusieurs années déjà les WebServices sont à la mode, pour rappel simpliste, un web service est en général une unité de code exposée au monde extérieur. La manière d'utiliser et de communiquer avec cette unité de code est décrite par une enveloppe SOAP (Simple Object Access Protocol). L'enveloppe SOAP décrit un contrat contenant les end-points (ou point d'accès), ainsi que le format des messages pouvant être transférés.

Les web services mettent l'accent sur le process des données, en général on accède à une fonctionalité.

REST (REpresentational State Transfer) donne une autre approche, ici on ne s'intéresse pas aux résultats d'un processing sur les données mais aux données elle même. D'un certain point de vue cette approche est intéressante puisqu'elle rejoins la définition originale des URI

Une URI (Uniform Resource Indentifier) permet d'identifier une ressources

Elle peut être soit une URN (Uniform Resource Name) : ex hello.html ou une URL (Uniform Resource Locator) : http://www.domain.be/hello.html

En général la plupart des URI ne servent pas à identifier ou localiser une resources mais a effectuer des actions:

ex: http://www.sdlg.be/sibyl/updateStudyItem?studyId=123

Ici on désigne clairement une action à effectuer sur une ressource en l'occurrence une study.

En technologie REST l'url aurait plutôt cette forme

http://www.sdlg.be/sibyl/studies/123

Un verbe sera également utilisé : GET, POST, PUT, DELETE.

La représentation des données peut se faire de diverses manières : HTML, XML, JSON

Le framework Spring utilise l'annotation @PathVariable pour récupérer le paramètre 123

De plus pour retourner du json, il faudra modifier le HTTP-HEADER en utilisant un bean de type:

ContentNegotiatingViewResolver et en le paramétrant pour json. Il faudra aussi installer l'artefact:

MappingJacksonHttpMessageConverter pour convertir les objets en flux json.

En PERL, on peut faire cela assez facilement avec JSON::PP (pure perl) ou JSON::XS (compilé en natif) qui contient la fonction to_json qui transforme une map ou une list de map en flux json.

Une rêquete GET en REST pourrait donc renvoyer un flux json représentant l'étude 123.

PUT permettrait de faire juste le contraire renvoyé l'état de l'étude 123 du client vers le serveur.

Avec l'utilisation de plus en plus fréquente de framework javascript basé sur AJAX une approche REST peut avoir quelques avantages non négligeables.

On peut bien sûr aller plus loin, comme SOAP, REST est basé sur HTTP (à la différence de SOAP, il se focalise sur l'état des objets, les données), donc il est possible de créer des clients REST n'ayant rien à voir avec un browser classique.

Il faut aussi noter que REST est nettement moins lourd que SOAP à la mise en oeuvre, maintenant Spring WS fait déjà beaucouop pour nous quant à la mise en place de WebService.


jeudi 29 mars 2012

Cross Tab queries en Oracle 10

Cross-tab queries ou Pivot en Oracle 10g.

Je sais qu'Oracle 11 introduit la notion de Pivot table qui permette de créer des cross tab queris (affichage d'une réponse classée dans un tableau par valeur d'une variable catégorielle). Les adorateurs de SAS connaissent cela via la procedure PROC TABLE qui peut faire un tantinet plus qu'afficher un simple tableau, puisque l'on peut aussi calculer un test de Khi carré mais bon même si mon blog est dédié au stat là n'est pas le sujet du billet d'aujourd'hui.
Par contre les utilisateurs d'Oracle 10 ne peuvent pas bénéficier de cette avancée (bien fait...). Il faut donc trouver un palliatif.
Je prends un cas usuel, nous avons des sujets et ces sujets on différentes propriétés 3 en l'occurrences dans notre exemple. Chaque sujet possède une valeur par propriété. En gros j'ai deux tables, une table sujet et une table propriété.

Une jointure entre les tables nous donne le tableau suivant: V1 et V2 sont des variables numériques, V3 est une variable de type texte.

Sujets
Sujet DOB
1 15/01/2000
2 1/1/1992

Variables
Sujet Nom Valeur
1 V1 15
1 V2 2
1 V3 test
1 V1 17
1 V2 3
1 V3 subj2

La jointure des tables sujets - variables nous donnent ceci

Sujet DOB Nom Valeur
1 15/01/2000 V1 15
1 15/01/2000 V2 2
1 15/01/2000 V3 test
2 1/1/1992 V1 17
2 1/1/1992 V2 3
2 1/1/1992 V3 subj2

Cette approche n'est pas très commode et souffre même d'un certain gigantisme tabulatoire.

Une approche simplificatrice consiste à utiliser une combinaison judicieuse de MAX et de DECODE afin de produire un tableau de type
Sujet V1 V2 V3
1 15 2 test
2 17 3 subj2

Ce que permet le bout de SQL suivant:
select Sujet, MAX(DECODE(Nom, 'V1', VALEUR, NULL)) IV1,
MAX(DECODE(Nom, 'V2', Valeur, NULL)) IV2,
MAX(DECODE(Nom, 'V3', Valeur, NULL)) IV3
FROM Variables
group by Sujet
order by Sujet;

Explication rapide : le DECODE affiche
Select Sujet, DECODE(Nom, 'V1', VALEUR, NULL) IV1,
DECODE(Nom, 'V2', Valeur, NULL) IV2,
DECODE(Nom, 'V3', Valeur, NULL) IV3
FROM Variables

Nous donne un tableau constitué du sujet auquel on concatène chaque valeur de V1, V2, V3. si la variable vaut V1 et qu'elle a une valeur alors sa valeur est affichée, sinon on affiche NULL

Cela nous donne

Sujet V1 V2 V3
1 15 null null
1 null 2 null
1 null null test
2 17 null null
2 null 3 null
2 null null subj2

On remarque que par sujet on obtient une matrice diagonale. L'utilisation d'un regroupement sur MAX permet d'éliminer les valeurs nulles.

Vous remarquerez qu'Oracle a une drôle d'interprétation de la nullité. Nous savons en effet que null signifie que l'on ne connaît pas la valeur. Si Alain à un age de 30 ans et Philippe un age inconnu que vaut le MAX(Age) entre Alain et Philippe. La réponse est normalement je ne sais pas. Pour Oracle la réponse est Alain. C'est assez divinatoire (sans mauvais jeu de mot) comme approche mais ça marche pour notre exemple, nous ne nous en plaindrons donc pas !

dimanche 25 mars 2012

Maven 2

Maven 2

est équivallent à la procédure de build management (produire un logiciel à partir de ses sources en automatisant certaines tâches)
Il gère aussi les dépendances (external jar).

Nomenklatura
artefact: élément spécifique de la construction du projet (en général des jar) mais ça peut -être des war, des ear, ...
dépendance: c'est une dépendance du projet vers un artefact
snapshot : version du projet en cours de développement.
POM : Project Object Model : paradigme qui décrit le projet logiciel, ses dépendances et l'ordre des tâches à effectuer pour le produire. Basé sur XML (pom.xml) mais un peu plus simple qu'ANT.

Ils fonctionnent en réseau, peut télécharger des jar venant de répository connus et gère aussi les dépendances récursives.

Le fichier POM.xml contient les propriétés du projet parent, il est possible de redéfinir ces propriétés (héritage).

Convention de répertoire MAVEN
/src
/src/main
/src/main/java
/src/main/resources (images, fichiers, annexe, ...)
/src/main/webapp

/src/test
/src/test/java
/src/test/resources

/src/site : information relative au projet généré
/src/target : executables, jar, ...

Cycle de vie

compile
test
package (crée le jar dans target)
install
deploy

Ces opérations sont des opérations basiques de building, et fonctionnent sous forme de plugins que l'on peut ajouter dans le project object model. On est donc pas figé à ces seules étapes du cycle de vie.

Limitations
Certains artefacts ont des license agreement et ne sont donc pas directement résolvable par maven.
Ex: javax.naming.jndi

Référence
http://java.developpez.com/faq/maven/?page=terminologie

lundi 13 février 2012

Binary Tree in JavaScript

Voici une méthode simple permattant de générer un Binary Tree en JScript. Pour l'instant on utilise que des valeurs de type numérique.
L'avantage étant qu'une recherche ne demande plus que n*log(n) plutôt que n*n...

// Simple Binary Tree
// This binary tree is containing a numeric value (or string)
// and is used to optimize search in list.
// Usage:
// tree = new BTree();
// tree.add(value);
//
// BTree.add() Method
// add a new value in the tree (if value is lesser than the current values a new child is created at the left,
// otherwise a new child is created at the right)
// INPUT: value : integer
// OUTPUT: true : if the value has been added (was not existing in the tree)
// false : value already exist in the Tree.

function BTreeNode (value, left, right) {
this._value=value;
this._left=left;
this._right=right;
}
function BTree() {
this.root=null;
this.add=function (value) {
var node;
if (this.root!=null) {
var lastNode=null;
lastNode=this.getNode(value, this.root);
if (lastNode._value==value)
return false; // if exist is not added
node=new BTreeNode(value, null, null);
if (valuenode._value) {
if (node._right!=null)
return this.getNode(value, node._right);
else
return node;
}

}
this.getNode=function (value, node) {
if (node==null)
return null;
if (valuenode._value) {
if (node._right!=null)
return this.getNode(value, node._right);
else
return node;
}

}

}



mardi 3 janvier 2012

Regexp en PERL

Opérateur Binding: =~
s'utilise avec les commandes suivantes:
m (match)
s (substitute) :/i (case insensitive)/g global
tr ou y (translation) /ex s/ba/ab/g ne marche pas par contre y/ba/ab/ lui fonctionne bien.

charactère spéciaux:
\s : space
\S : non space
\d : digit
\D : non digit
\w : word

Exemple : récupérer et supprimer le dernier espace dans une chaine de caracètre:
$str=~s/(\s+\S*$)//;
print $1;
Je recherche au moins un espacedans une chaine qui se termine par 0 ou 1 non espace.
Perl stocke le contenu de la paranthèse (\s+\S*$) dans la variable $1

Trim d'une chaine de caractère
$str=~s/^\s+//; # éliminie les espaces de débuts
$str=~s/\s+$//; # élimine les espaces de fins

Vérification d'une adresse mail (simple):
$str~=m/[a-zA-Z0-9-.]+\@[a-zA-Z0-9-.]+

Vérifier qu'une chaine de caractère contient un opérateur:
$str~=m/\*|\+|\/|\\|\(|\)|\s|\^|#|\||'|\"|=|!