Planet

La communauté francophone d’Ubuntu, du haut de ses neuf ans, est bien motivée à continuer de promouvoir Ubuntu et les logiciels libres auprès du grand public !

À Paris, c’est une centaine de bénévoles qui organiseront ce weekend (16 et 17 novembre) le plus grand événement de promotion du Libre de la région. Dans un grand espace dédié au numérique, au sous-sol de la Cité des sciences et de l’industrie, la dix-septième ubuntu party parisienne proposera 25 conférences petites et grandes, 12 cours d’initiation, 28 démonstrations, un micro village associatif, un espace jeunesse, et, bien sûr, une install party où les visiteurs seront accompagnés dans leur passage de Windows/mac à Ubuntu.

À Toulouse, Le Capitole du Libre co-organisé avec Toulibre ces 23 et 24 novembre, accueillera comme toujours une Ubuntu Party aux cotés de nombreuses conférences pour découvrir et comprendre le monde du Logiciel Libre, comprendre ce qu’est l’OpenData, la culture libre et les biens communs. Une LAN Party pour découvrir les jeux libres y est même organisée ! Consultez le programme.

À Sarrebourg, « La journée du Libre » est le nom donné à l’Ubuntu Party qui se tiendra le samedi 23 novembre, organisée par la communauté Ubuntu Sarrebourg. Là aussi, une install party pour le grand public, accompagnée de conférences sur Blender, Gimp, les différents environnements de bureau, OpenStreetMap. Particularité de cet Ubuntu Party, la « bourse informatique » pour redonner vie aux PC à bout de souffle.

Venez et faites venir vos amis aux Ubuntu Party et faites-en la promotion sur les réseaux sociaux ! (@ubuntuparty et +ubuntu-fr)

Premiers pas avec Ubuntu 13.10 - CouvertureLes traductions sont au cœur de la philosophie Ubuntu :

  • chacun doit avoir la liberté de télécharger, exécuter, copier, distribuer, étudier, partager, modifier et améliorer le logiciel ;
  • chacun doit avoir l’opportunité d’utiliser le logiciel, même en cas de handicap ;
  • chacun doit avoir le droit d’utiliser le logiciel dans la langue de son choix.

C’est pour cela qu’aujourd'hui nous sommes heureux et fiers de vous annoncer la sortie de la version française du célèbre Manuel Ubuntu pour Ubuntu 13.10. Le manuel vous fournit de manière claire et structurée tout ce dont vous avez besoin pour débuter puis progresser avec Ubuntu. Le Manuel Ubuntu est aussi la garantie d’instructions pas à pas qui marchent, testées et intégralement en français, sans barbarismes ni mots incompréhensibles.

Pour résumer les avantages du manuel :

  • facile à appréhender – notre manuel comprend des instructions pas à pas et est dénué de jargon technique ;
  • une illustration vaut bien mieux qu’une longue description – beaucoup de captures d’écran illustrent les instructions ;
  • tout au même endroit – vous n’avez pas à parcourir le Web pour trouver de l’aide car tout se trouve dans un seul fichier ;
  • apprentissage progressif – démarrez avec les bases et apprenez au travers des différents chapitres ;
  • des dizaines de langues – traduit en plus de 52 langues, y compris des copies d’écran localisées ;
  • sous licence CC-BY-SA – téléchargez, modifiez, reproduisez et partagez autant que vous voulez ;
  • aucun coût – nos documents sont tous rédigés par des membres de la communauté Ubuntu et leur utilisation est gratuite ;
  • imprimable – cette version est optimisée pour l’impression afin de sauver les arbres ;
  • section de diagnostic des problèmes – pour vous aider à régler rapidement les problèmes courants sous Ubuntu.

 

Télécharger le Manuel

Télécharger le manuel (13.10)

Liens directs : Ecran - Impression


Commander une version papier (13.10) sur CreateSpace (4,69 $ + frais de port)

Commander une version papier sur amazon.fr (13.10) (4,34 €, frais de port inclus)

Contribuer à la traduction d’Ubuntu et de sa documentation

 

 

Image: 

Premiers pas avec Ubuntu 13.10 - CouvertureLes traductions sont au cœur de la philosophie Ubuntu :

  • chacun doit avoir la liberté de télécharger, exécuter, copier, distribuer, étudier, partager, modifier et améliorer le logiciel ;
  • chacun doit avoir l’opportunité d’utiliser le logiciel, même en cas de handicap ;
  • chacun doit avoir le droit d’utiliser le logiciel dans la langue de son choix.

C’est pour cela qu’aujourd'hui nous sommes heureux et fiers de vous annoncer la sortie de la version française du célèbre Manuel Ubuntu pour Ubuntu 13.10. Le manuel vous fournit de manière claire et structurée tout ce dont vous avez besoin pour débuter puis progresser avec Ubuntu. Le Manuel Ubuntu est aussi la garantie d’instructions pas à pas qui marchent, testées et intégralement en français, sans barbarismes ni mots incompréhensibles.

Pour résumer les avantages du manuel :

  • facile à appréhender – notre manuel comprend des instructions pas à pas et est dénué de jargon technique ;
  • une illustration vaut bien mieux qu’une longue description – beaucoup de captures d’écran illustrent les instructions ;
  • tout au même endroit – vous n’avez pas à parcourir le Web pour trouver de l’aide car tout se trouve dans un seul fichier ;
  • apprentissage progressif – démarrez avec les bases et apprenez au travers des différents chapitres ;
  • des dizaines de langues – traduit en plus de 52 langues, y compris des copies d’écran localisés ;
  • sous licence CC-BY-SA – téléc hargez, modifiez, reproduisez et partagez autant que vous voulez ;
  • aucun coût – nos documents sont tous rédigés par des membres de la communauté Ubuntu et leur utilisation est gratuite ;
  • imprimable – cette version est optimisée pour l’impression afin de sauver les arbres ;
  • section de diagnostic des problèmes – pour vous aider à régler rapidement les problèmes courants sous Ubuntu.

 

Télécharger le Manuel

Télécharger le manuel (13.10)

Liens directs : Ecran - Impression


Commander une version papier (13.10) sur CreateSpace (4,69 $ + frais de port)

Commander une version papier sur amazon.fr (13.10) (bientôt disponible, frais de port inclus)

Contribuer à la traduction d’Ubuntu et de sa documentation

 

 

Image: 

Fork me on GitHub

 

J'ai parlé récemment d'un script qui permet de poster automatiquement un tweet quand je publie un nouvel article sur le blog.

Ce script a été un peu modifié puisqu'il fait aujourd'hui 4 choses :

  1. Il vérifie si un nouvel article a été écrit (en cherchant la présence du message [POST] au début du message de commit Git) ;
  2. Dans ce cas, il envoie les nouveaux commits sur le dépôt Git défini par défaut ;
  3. Il met à jour le blog sur le serveur via SSH (commande make ssh_upload pour les Pelican-eux) ;
  4. Il envoie un tweet.

Tout ça c'est sympa, mais c'est un peu con d'automatiser toutes ces étapes si il faut au final lancer le script à la main. La magie de Git fait qu'on peut automatiser tout ça en utilisant les hooks de Git.

Ces hooks sont des scripts que Git lance après (ou avant) certaines étapes de son processus. Ils sont listés dans le répertoire .git/hooks/ :

╭────<quack@spiderman >───< ~/Documents/writing/blog/quack1_pelican > ‹master*› ╰───[18:52:40] $ ls .git/hooks applypatch-msg.sample post-commit pre-applypatch.sample prepare-commit-msg.sample update.sample commit-msg.sample post-update.sample pre-commit.sample pre-rebase.sample

Je ne vais pas tous les faire, les noms sont assez explicites, mais par exemple pre-commit est lancé avant le commit.

Mon script a besoin que le commit soit terminé, donc j'ai fait pointer le fichier .git/hooks/post-commit sur le script. Toute la configuration nécessaire est placée dans le fichier de conf, donc le script se lance sans souci :

╭────<quack@spiderman >───< ~/Documents/writing/blog/quack1_pelican > ‹master*› ╰───[18:53:14] $ ln -s ~/work/workspace/python/pelican_auto_tweet/pelican_auto_tweet.py .git/hooks/post-commit

Désormais dès que vous ferez un commit dans ce dépôt Git, le script se lancera et si toutes les conditions sont réunies, votre blog se mettra à jour, et un tweet sera posté !

 

Le dépôt GitHub du projet est à jour, et possède déjà quelques issues que j'avais trouvé sur les scripts et que je dois corriger. Si vous utilisez les scripts, et que vous trouvez des bugs, n'hésitez pas à me les remonter, je corrigerais ça rapidement !

 

J'ai parlé récemment d'un script qui permet de poster automatiquement un tweet quand je publie un nouvel article sur le blog.

Ce script a été un peu modifié puisqu'il fait aujourd'hui 4 choses :

  1. Il vérifie si un nouvel article a été écrit (en cherchant la présence du message [POST] au début du message de commit Git) ;
  2. Dans ce cas, il envoie les nouveaux commits sur le dépôt Git défini par défaut ;
  3. Il met à jour le blog sur le serveur via SSH (command make ssh_upload pour les Pelican-eux) ;
  4. Il envoie un tweet.

Tout ça c'est sympa, mais c'est un peu con d'automatiser toutes ces étapes si il faut au final lancer le script à la main. La magie de Git fait qu'on peut automatiser tout ça en utilisant les hooks de Git.

Ces hooks sont des scripts que Git lance après (ou avant) certaines étapes de son processus. Ils sont listés dans le répertoire .git/hooks/ :

╭────<quack@spiderman >───< ~/Documents/writing/blog/quack1_pelican > ‹master*› ╰───[18:52:40] $ ls .git/hooks applypatch-msg.sample post-commit pre-applypatch.sample prepare-commit-msg.sample update.sample commit-msg.sample post-update.sample pre-commit.sample pre-rebase.sample

Je ne vais pas tous les faire, les noms sont assez explicites, mais par exemple pre-commit est lancé avant le commit.

Mon script a besoin que le commit soit terminé, donc j'ai fait pointer le fichier .git/hooks/post-commit sur le script. Toute la configuration nécéssaire est placée dans le fichier de conf, donc le script se lance sans souci :

╭────<quack@spiderman >───< ~/Documents/writing/blog/quack1_pelican > ‹master*› ╰───[18:53:14] $ ln -s ~/work/workspace/python/pelican_auto_tweet/pelican_auto_tweet.py .git/hooks/post-commit

Désormais dès que vous ferez un commit dans ce dépôt Git, le script se lancera et si toutes les conditions sont réunies, votre blog se mettra à jour, et un tweet sera posté !

 

Le dépôt GitHub du projet est à jour, et possède déjà quelques issues que j'avais trouvé sur les scripts et que je dois corriger. Si vous utilisez les scripts, et que vous trouvez des bugs, n'hésitez pas à me les remonter, je corrigerais ça rapidement !

2561885967_f5f0be5834_n.jpgMe voila avec un index flambant neuf ( ou presque) importé en presque 30 minutes. Je n’ai plus qu’à rechercher. Voici ce qu’on peut faire assez simplement "out of the box":

Via l’interface d’administration

L’interface d’administration possède déjà un outil de recherche assez simple d’utilisation. On renseigne le critère de recherche et on obtient la réponse au format souhaité ( JSON, XML, PYTHON, CSV,…)

backup_sonar036.png

Cette option peut être intéressante pour une interface d’administration

Via une requête REST

J’ai fait un simple appel REST avec JERSEY pour effectuer la même requête. J’ai utilisé le mapping des POJO pour mapper la réponse à mon bean.

On retrouve les mêmes paramètres

  1. public class RESTQueryTest {
  2.  
  3. private final static String QUERY_URL = "http://127.0.0.1:8080/customers/customers/select";
  4. public static final int HTTP_STATUS_OK = 200;
  5. private Client client;
  6. private WebResource queryWebResource;
  7. private ClientConfig clientConfig;
  8. private String MAX_ROWS;
  9.  
  10. @Before
  11. public void setUp() throws Exception {
  12. clientConfig = new DefaultClientConfig();
  13. clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
  14. client = Client.create(clientConfig);
  15. queryWebResource = client.resource(QUERY_URL);
  16. }
  17.  
  18. @Test
  19. public void testQueryByLastName() throws Exception {
  20. MultivaluedMap<String, String> parameters = new MultivaluedMapImpl();
  21. parameters.add("q", "lastname:JAN");
  22. parameters.add("wt", "json");
  23.  
  24. ClientResponse response = queryWebResource.queryParams(parameters).type(MediaType.TEXT_PLAIN_TYPE).
  25. accept(MediaType.APPLICATION_JSON_TYPE, MediaType.TEXT_PLAIN_TYPE).get(ClientResponse.class);
  26. assertEquals(response.getStatus(), HTTP_STATUS_OK);
  27. }
  28.  
  29. @Test
  30. public void testQueryFuzzy() throws Exception {
  31. MultivaluedMap<String, String> parameters = new MultivaluedMapImpl();
  32. final String FUZZY_QUERY_BY_LASTNAME = "lastname:JAN~";
  33. parameters.add("q", FUZZY_QUERY_BY_LASTNAME);
  34. parameters.add("wt", "json");
  35. parameters.add("indent", "true");
  36. final int MAX_ROWS = 20;
  37. parameters.add("rows", String.valueOf(MAX_ROWS));
  38.  
  39. ClientResponse response = queryWebResource.queryParams(parameters).type(MediaType.APPLICATION_JSON_TYPE).
  40. accept(MediaType.APPLICATION_JSON_TYPE, MediaType.TEXT_PLAIN_TYPE).get(ClientResponse.class);
  41. assertEquals(response.getStatus(), HTTP_STATUS_OK);
  42. SOLRResponse<CustomerResource> solrResponse=response.getEntity(new GenericType<SOLRResponse<CustomerResource>>(){});
  43. assertNotNull(solrResponse);
  44. assertEquals(solrResponse.getResponse().getDocs().size(), MAX_ROWS);
  45. assertEquals(solrResponse.getResponseHeader().getParams().getQuery(),FUZZY_QUERY_BY_LASTNAME);
  46. }
  47. }

La classe SOLRResponse décrit la réponse JSON, Elle est annotée avec JAXB.

  1. @XmlRootElement
  2. public class SOLRResponse<T> {
  3.  
  4. private SOLRResponseHeader responseHeader ;
  5. private SOLRResponseBody<T> response;
  6.  
  7. public SOLRResponseBody<T> getResponse() {
  8. return response;
  9. }
  10.  
  11. public void setResponse(SOLRResponseBody<T> response) {
  12. this.response = response;
  13. }
  14.  
  15. public SOLRResponseHeader getResponseHeader() {
  16. return responseHeader;
  17. }
  18.  
  19. public void setResponseHeader(SOLRResponseHeader responseHeader) {
  20. this.responseHeader = responseHeader;
  21. }
  22.  
  23.  
  24. }

J’ai rendu cette réponse générique pour ensuite appliquer ce que l’on veut dans les documents (ex. Classe CustomerResource)

Via l’API SOLRJ

Pré-requis

Ajouter la dépendance solr au projet

  1. <dependency>
  2. <groupId>org.apache.solr</groupId>
  3. <artifactId>solr-solrj</artifactId>
  4. <version>${solr.version}</version>
  5. </dependency>

Je trouve cette solution beaucoup plus simple à mettre en oeuvre. Elle prend dynamiquement les champs de la réponse ( qui peuvent changer selon les paramètres d’appels ). De plus il n’y a pas besoin de décrire l’enveloppe de la réponse comme en REST.

  1. public class JavaQueryTest {
  2.  
  3. private final static String QUERY_URL = "http://127.0.0.1:8080/customers/customers";
  4. private HttpSolrServer solrServer;
  5. private SolrQuery solrQuery;
  6.  
  7. @Before
  8. public void setUp() throws Exception {
  9. solrServer = new HttpSolrServer(QUERY_URL);
  10. solrServer.setAllowCompression(true);
  11. solrServer.setMaxRetries(5);
  12. solrQuery = new SolrQuery();
  13. }
  14.  
  15. @Test
  16. public void testQueryFuzzy() throws Exception {
  17. solrQuery.setQuery("TOURET~");
  18. solrQuery.addSort("dtcrea", SolrQuery.ORDER.asc);
  19. QueryResponse response = solrServer.query(solrQuery);
  20. assertNotNull(response);
  21. assertNotNull(response.getResults());
  22. assertFalse(response.getResults().isEmpty());
  23. System.out.println("Premier champ:" + response.getResults().get(1).toString());
  24. List<CustomerResource> customers = response.getBeans(CustomerResource.class);
  25. assertNotNull(customers);
  26. assertFalse(customers.isEmpty());
  27. }
  28. }

Depuis un bon moment déjà j'écris tout en Markdown. Ce blog — et l'autre —, mes notes (avec RedNotebook entre autres), et encore plein d'autres choses de cette façon. Seul le boulot et sa suite Office me résistent encore 😋 !

Pour écrire tout ça j'utilise Sublime Text, qui est un excellent éditeur de texte. Véritable IDE, il est à la base dédié à l'édition de code source.

Du coup, quand on veut écrire du texte dedans, c'est pas super agréable...

L'avantage de Sublime-Text, c'est que chaque utilisateur peut redéfinir des préférences, qui surchargent celles par défaut. Et cerise sur le gâteau, on peut redéfinir des préférences pour chaque extension de fichiers! Et c'est justement cette fonctionnalité qui m'intéresse.

Maintenant, quand j'écris du Markdown, ça ressemble à ça :

Pour modifier la configuration de Sublime Text, ouvrez un fichier Markdown (chez moi avec l'extension .md), et allez dans PréférencesSettings - MoreSyntax Specific - User.

Mon fichier de configuration ressemble à ça :

{ "extensions": [ "md" ], "auto_complete": true, "spell_check": true, "dictionary": "Packages/Language - French - Français/fr_FR (all variants).dic", "draw_centered": true, "word_wrap": "True", "wrap_width": 80, "font_size": 9, "gutter": false, "line_numbers": false, "line_padding_bottom": 2, "line_padding_top": 2, "scroll_past_end": true, "tab_size": 6 }

Ligne par ligne, qu'est ce que ça fait :

  • "extensions" désigne les extensions pour lesquelles ce fichier s'applique ;
  • "auto_complete" active la complétion automatique avec <TAB> ;
  • "spell_check" active la vérification orthographique ;
  • "dictionary" pointe sur le dictionnaire à utiliser pour la vérification orthographique (les dictionnaires proviennent de Libre Office) ;
  • "draw_centered" centre le texte dans la fenêtre ;
  • "word_wrap" coupe les lignes lors de l'affichage après X caractères ;
  • "wrap_width" désigne le nombre de caractères avant de couper la ligne ;
  • "font_size" défini la taille de la police de caractères ;
  • "gutter" je ne sais pas ce que ça fait, mais c'est défini à false dans le mode Distraction Free, donc je pense que ce n'est pas mauvais... ;
  • "line_numbers" désactive l'affichage du nombre de lignes, mais je songe à le réactiver... ;
  • "line_padding_bottom"et "line_padding_top" ajoutent de l'espacement au-dessous et au-dessus des lignes de texte, pour l'aérer ;
  • "scroll_past_end" permet de faire défiler le texte même quand on arrive à la fin du fichier ;
  • "tab_size" augmente le nombre d'espaces à utiliser pour les tabulations (en réalité Sublime Text utilise bien le caractère <TAB>, mais cette tabulation est affichée pour quelle corresponde à 6 espaces).

Plus d'options sont disponibles dans la doc de Sublime Text. Je ne pense pas avoir pensé à tout, si vous trouvez comment améliorer encore cette configuration, n'hésitez pas!

Depuis un bon moment déjà j'écris tout en Markdown. Ce blog — et l'autre —, mes notes (avec RedNotebook entre autres), et encore plein d'autres choses de cette façon. Seul le boulot et sa suite Office me résistent encore 😋 !

Pour écrire tout ça j'utilise Sublime Text, qui est un excellent éditeur de texte. Véritable IDE, il est à la base dédié à l'édition de code source.

Du coup, quand on veut écrire du texte dedans, c'est pas super agréable...

L'avantage de Sublime-Text, c'est que chaque utilisateur peut redéfinir des préférences, qui surchargent celles par défaut. Et cerise sur le gâteau, on peut redéfinir des préférences pour chaque extension de fichiers! Et c'est justement cette fonctionnalité qui m'intéresse.

Maintenant, quand j'écris du Markdown, ça ressemble à ça :

Pour modifier la configuration de Sublime Text, ouvrez un fichier Markdown (chez moi avec l'extension .md), et allez dans PréférencesSettings - MoreSyntax Specific - User.

Mon fichier de configuration ressemble à ça :

{ "extensions": [ "md" ], "auto_complete": true, "spell_check": true, "dictionary": "Packages/Language - French - Français/fr_FR (all variants).dic", "draw_centered": true, "word_wrap": "True", "wrap_width": 80, "font_size": 9, "gutter": false, "line_numbers": false, "line_padding_bottom": 2, "line_padding_top": 2, "scroll_past_end": true, "tab_size": 6 }

Ligne par ligne, qu'est ce que ça fait :

  • "extensions" désigne les extensions pour lesquelles ce fichier s'applique ;
  • "auto_complete" active la complétion automatique avec <TAB> ;
  • "spell_check" active la vérification orthographique ;
  • "dictionary" pointe sur le dictionnaire à utiliser pour la vérification orthographique (les dictionnaires proviennent de Libre Office) ;
  • "draw_centered" centre le texte dans la fenêtre ;
  • "word_wrap" coupe les lignes lors de l'affichage après X caractères ;
  • "wrap_width" désigne le nombre de caractères avant de couper la ligne ;
  • "font_size" défini la taille de la police de caractères ;
  • "gutter" je ne sais pas ce que ça fait, mais c'est défini à false dans le mode Distraction Free, donc je pense que ce n'est pas mauvais... ;
  • "line_numbers" désactive l'affichage du nombre de lignes, mais je songe à le réactiver... ;
  • "line_padding_bottom"et "line_padding_top" ajoutent de l'espacement au-dessous et au-dessus des lignes de texte, pour l'aérer ;
  • "scroll_past_end" permet de faire défiler le texte même quand on arrive à la fin du fichier ;
  • "tab_size" augmente le nombre d'espaces à utiliser pour les tabulations (en réalité Sublime Text utilise bien le caractère <TAB>, mais cette tabulation est affichée pour quelle corresponde à 6 espaces).

Plus d'options sont disponibles dans la doc de Sublime Text. Je ne pense pas avoir pensé à tout, si vous trouvez comment améliorer encore cette configuration, n'hésitez pas!

29 Octobre 2013 à 09:18

Import des données dans un index SOLR via Littlewing

3650487959_d5cac67af6_n.jpg[1]

Comme j’ai pu l’indiquer dans mon précédent billet, je me suis mis en tête d’indexer les données issues d’une base clients. J’ai lancé un simple import . Voici le résultat :

backup_sonar035.png

J’ai donc indexé 19288644 clients en 35 minutes .

Si on regarde du coté de l’espace disque, on obtient la taille suivante :

  1. $ du -h
  2. 592M ./data/index
  3. 3,3M ./data/tlog
  4. 595M ./data
  5. 596M .

Les temps d’exécution des requêtes sont déjà très satisfaisants sans aucune optimisation.

Note

[1] Photo sous licence creative commons

28 Octobre 2013 à 16:23

Premiers pas avec SOLR via Littlewing

Après avoir pas mal touché à Apache Lucene il y a quelques années ce ça ( je vous par le d’un temps que les moins de vingt ans ne peuvent pas connaître…), j’ai décidé de me pencher sur les moteurs de recherche opensource. J’ai donc décidé de me pencher sur SOLR et ElasticSearch. Ces deux projets sont basés sur lucene.

Le cas d’utilisation que je souhaite mettre en œuvre est assez simple pour l’instant : indexer le résultat d’une requête faite dans un SGBD. Celle ci prend énormément de temps ( environ 30 secondes ) et je souhaite avoir un résultat immédiat le tout en REST.

Le cas elasticsearch

J’ai tout d’abord essayé elasticsearch. Ce dernier est le projet qui a le vent en poupe et présente de nombreux sous-projets très intéressants ( logstash, kibana). Le seul moyen d’extraire les données d’un SGBD est le jdbc-river. Ce moyen ne m’a pas trop séduit , il y a pas mal de problèmes liés à la saisie d’une requête complexe. Aussi j’en ai discuté brièvement avec David Pilato ( qui a fait une super présentation sur Kibana) lors du JugSummerCamp . Il m’a confirmé l’extension du scope du projet logstash aux autres sources de données (ex. JDBC). Cette mutation devrait être effective mi 2014. Bref, en attendant j’ai exploré SOLR.

Présentation de SOLR

SOLR est donc un moteur de recherche ( ça vous l’aviez deviné) qui s’appuie sur Apache Lucene ( ça aussi …) . Il présente des fonctionnalités semblables à ElasticSearch. A ce que j’ai pu lire sur le net ici ou , ce dernier est supérieur sur la gestion des recherches distribuées. Je n’aurais pas besoin de cette fonctionnalité dans un premier temps. Les fonctionnalités qui m’intéressent sont les suivantes :

  • Les API JAVA et REST
  • Le facets
  • La mise en avant de certaines recherches
  • Les requêtes geo spatiales
  • La réplication des données

Configuration

Pour mon projet, je me suis basé sur un archetype maven disponible sur le net. Ce dernier crée un exemple de projet qui lance un jetty avec le war de solr

Vous devez également disposer de la distribution de SOLR pour que le livrable soit déployé. C’est la seule solution que j’ai trouvé pour l’instant. Ce n’est pas très élégant, car je préférerai avoir le tout embarqué dans la webapp.

Mon projet s’appelle customer-indexer . Il indexe les données d’une base de clients. Dans le répertoire src/main/resources, j’ai crée un répertoire customers. J’ai copié le contenu du répertoire collection1 présent dans les exemples de la distribution.

J’exposerai ici la configuration indispensable pour mon cas d’étude

le fichier solr.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <solr persistent="true">
  3. <cores adminPath="/admin/cores" defaultCoreName="refper" host="${host:}" hostPort="${jetty.port:}" hostContext="${hostContext:}" zkClientTimeout="${zkClientTimeout:15000}">
  4. <core name="customers" instanceDir="." />
  5. </cores>
  6. </solr>

Dans le répertoire src/main/resources/customers/conf, il faut ajouter a minima les fichiers solrconfig.xml schema.xml et data-config.xml.

solrconfig.xml

Les deux premiers sont déjà présents J’ai modifié le premier avec les informations suivantes :

j’ai mis le chemin en dur de la distribution et non le relatif

  1. <lib dir="c:/java/solr-4.5.0/contrib/extraction/lib" regex=".*\.jar" />
  2. <lib dir="c:/java/solr-4.5.0/dist/" regex="solr-cell-\d.*\.jar" />
  3.  
  4. <lib dir="c:/java/solr-4.5.0/contrib/clustering/lib/" regex=".*\.jar" />
  5. <lib dir="c:/java/solr-4.5.0/dist/" regex="solr-clustering-\d.*\.jar" />
  6. <lib dir="c:/java/solr-4.5.0/dist/" regex="solr-dataimporthandler-\d.*\.jar" />
  7.  
  8. <lib dir="c:/java/solr-4.5.0/contrib/langid/lib/" regex=".*\.jar" />
  9. <lib dir="c:/java/solr-4.5.0/dist/" regex="solr-langid-\d.*\.jar" />
  10.  
  11. <lib dir="c:/java/solr-4.5.0/contrib/velocity/lib" regex=".*\.jar" />
  12. <lib dir="c:/java/solr-4.5.0/dist/" regex="solr-velocity-\d.*\.jar" />

La configuration de l’élément elevator semblait erronée

  1. <searchComponent name="elevator" class="solr.QueryElevationComponent" >
  2. <!-- pick a fieldType to analyze queries -->
  3. <str name="queryFieldType">string</str>
  4. <str name="config-file">elevate.xml</str>
  5. </searchComponent>

J’ai rajouté également le module d’import des données

  1. <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
  2. <lst name="defaults">
  3. <str name="config">data-config.xml</str>
  4. </lst>
  5. </requestHandler>

schema.xml

Ce fichier décrit la structure des documents présents dans l’index du moteur de recherche. On définit les données à indexer, les types de données et les filtres à appliquer (exemple: tout passer en minuscule)

  1. <schema name="customers" version="1.5">
  2. <fields>
  3.  
  4. <field name="idpp" type="string" indexed="true" stored="true" required="true" multiValued="false"/>
  5.  
  6. <!-- points to the root document of a block of nested documents -->
  7. <field name="_root_" type="string" indexed="true" stored="false"/>
  8.  
  9.  
  10. <field name="dtcrea" type="date" indexed="true" stored="true" omitNorms="true"/>
  11. <field name="dtlastupd" type="date" indexed="true" stored="true"/>
  12. <field name="title" type="lowercase" indexed="true" stored="true" omitNorms="true"/>
  13. <field name="lastname" type="lowercase" indexed="true" stored="true" multiValued="true"/>
  14. <field name="fstname" type="lowercase" indexed="true" stored="true" multiValued="true"/>
  15. <field name="dtbirth" type="date" indexed="true" stored="true" termVectors="true" termPositions="true"
  16. termOffsets="true"/>
  17. <field name="status" type="float" indexed="true" stored="true"/>
  18. <field name="content" type="text_general" indexed="false" stored="true" multiValued="true"/>
  19.  
  20. <!-- catchall field, containing all other searchable text fields (implemented
  21. via copyField further on in this schema -->
  22. <field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>
  23.  
  24. <!-- catchall text field that indexes tokens both normally and in reverse for efficient
  25. leading wildcard queries. -->
  26. <field name="text_rev" type="text_general_rev" indexed="true" stored="false" multiValued="true"/>
  27. <field name="_version_" type="long" indexed="true" stored="true"/>
  28.  
  29.  
  30. </fields>
  31. <uniqueKey>idpp</uniqueKey>
  32.  
  33. <!-- les copies permettent d'avoir tout le contenu dans un seul champ-->
  34. <copyField source="title" dest="text"/>
  35. <copyField source="lastname" dest="text"/>
  36. <copyField source="firstname" dest="text"/>
  37. <copyField source="birthday" dest="text"/>
  38. </schema>

data-config.xml

Dans ce fichier on spécifie les données récupérées de la base de données

  1. <dataConfig>
  2. <dataSource driver="oracle.jdbc.OracleDriver" url="urljdbc" user="user" password="pwd"/>
  3. <document name="customer">
  4. <entity name="customer" query="Marequete">
  5. <field column="id" name="id" />
  6. <field column="LASTNAME" name="lastname" />
  7. <field column="FIRSTNAME" name="firstname" />
  8. <field column="DTCREATION" name="dtcreation" />
  9. <field column="DTLASTUPDATE" name="dtlastupdate" />
  10. <field column="BIRTHDAY" name="birthday" />
  11. <field column="STATUS" name="status" />
  12. </entity>
  13. </document>
  14. </dataConfig>

Configuration maven

voici le contenu du pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6.  
  7. <groupId>customer-indexer</groupId>
  8. <artifactId>customer-indexer</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. <packaging>war</packaging>
  11.  
  12. <properties>
  13. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  14. <slf4j-api.version>1.7.5</slf4j-api.version>
  15. <log4j.version>1.2.17</log4j.version>
  16. <solr.version>4.5.0</solr.version>
  17. <solr.default.core.directory>customers</solr.default.core.directory>
  18. <solr.default.core.name>customers</solr.default.core.name>
  19. <solr.solr.home>c:/java/solr-4.5.0/</solr.solr.home>
  20. </properties>
  21.  
  22. <dependencies>
  23. <!-- SLF4J -->
  24. <dependency>
  25. <groupId>org.slf4j</groupId>
  26. <artifactId>slf4j-api</artifactId>
  27. <version>${slf4j-api.version}</version>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.slf4j</groupId>
  31. <artifactId>jcl-over-slf4j</artifactId>
  32. <version>${slf4j-api.version}</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.slf4j</groupId>
  36. <artifactId>jul-to-slf4j</artifactId>
  37. <version>${slf4j-api.version}</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.slf4j</groupId>
  41. <artifactId>slf4j-log4j12</artifactId>
  42. <version>${slf4j-api.version}</version>
  43. </dependency>
  44. <!-- Log4j -->
  45. <dependency>
  46. <groupId>log4j</groupId>
  47. <artifactId>log4j</artifactId>
  48. <version>${log4j.version}</version>
  49. </dependency>
  50.  
  51. <dependency>
  52. <groupId>com.oracle.ojdbc</groupId>
  53. <artifactId>ojdbc</artifactId>
  54. <version>10.2.0.2.0</version>
  55.  
  56. </dependency>
  57. <!-- Solr 4.3.0 -->
  58. <dependency>
  59. <groupId>org.apache.solr</groupId>
  60. <artifactId>solr</artifactId>
  61. <version>${solr.version}</version>
  62. <type>war</type>
  63. </dependency>
  64. </dependencies>
  65.  
  66. <build>
  67. <finalName>customers</finalName>
  68. <resources>
  69. <resource>
  70. <filtering>true</filtering>
  71. <directory>src/main/resources</directory>
  72. </resource>
  73. </resources>
  74. <plugins>
  75. <plugin>
  76. <artifactId>maven-antrun-plugin</artifactId>
  77. <version>1.7</version>
  78. <executions>
  79. <execution>
  80. <id>copy-to-solr</id>
  81. <goals>
  82. <goal>run</goal>
  83. </goals>
  84. <phase>package</phase>
  85. <configuration>
  86. <target>
  87. <copy todir="${solr.solr.home}" includeemptydirs="true" overwrite="true">
  88. <fileset dir="${project.build.outputDirectory}">
  89. </fileset>
  90. </copy>
  91. </target>
  92. </configuration>
  93. </execution>
  94. </executions>
  95. </plugin>
  96. <plugin>
  97. <groupId>org.eclipse.jetty</groupId>
  98. <artifactId>jetty-maven-plugin</artifactId>
  99. <version>9.0.4.v20130625</version>
  100. <configuration>
  101. <stopPort>9966</stopPort>
  102. <stopKey>stop</stopKey>
  103. <webApp>
  104. <contextPath>/refper</contextPath>
  105. </webApp>
  106. </configuration>
  107. </plugin>
  108. </plugins>
  109. </build>
  110. </project>

Démarrage

Dans mon cas il me suffit de lancer la commande

  1. mvn clean install jetty:run

Import des données

On peut le faire soit par un appel REST, soit par la console : Sélectionner la collection puis cliquer sur Data Import

backup_sonar034.png

Conclusion

Pour l’instant j’ai rapidement fait une première indexation de mes données. je suis conscient qu’il y a pas mal d’améliorations à apporter, notamment sur la modélisation de mon index avec les bonnes entités (ex. une entité customer, une entité address,…)

Je verrai le requêtage dans un autre post.

Pages