L'histoire d'un petit projet de douze ans (sur BIRMA.NET pour la première fois et franchement de première main)

La naissance de ce projet peut être considérée comme une petite idée qui m'est venue quelque part fin 2007, et qui était destinée à trouver sa forme définitive seulement 12 ans plus tard (à ce moment-là - bien sûr, même si la mise en œuvre actuelle, selon pour l'auteur, est très satisfaisant).

Tout a commencé lorsque, dans le cadre de l'exercice de mes fonctions alors officielles à la bibliothèque, j'ai attiré l'attention sur le fait que le processus de saisie des données du texte numérisé des tables des matières des publications de livres (et de musique) dans la base de données existante, apparemment, peut être considérablement simplifié et automatisé, en profitant de la propriété d'ordre et de répétabilité de toutes les données nécessaires à la saisie, comme le nom de l'auteur de l'article (si nous parlons d'une collection d'articles), le titre de l'article (ou le sous-titre reflété dans la table des matières) et le numéro de page de l'élément actuel de la table des matières. Au début, j'étais pratiquement convaincu qu'un système adapté à cette tâche pouvait être facilement trouvé sur Internet. Lorsqu'une certaine surprise a été provoquée par le fait que je ne trouvais pas un tel projet, j'ai décidé d'essayer de le mettre en œuvre par moi-même.

Après un temps assez court, le premier prototype a commencé à fonctionner, que j'ai immédiatement commencé à utiliser dans mes activités quotidiennes, en le déboguant simultanément sur tous les exemples qui me sont parvenus. Heureusement, sur mon lieu de travail habituel, où je n'étais en aucun cas programmeur, je m'en suis quand même sorti avec des « temps d'arrêt » visibles dans mon travail, pendant lesquels je déboguais intensément mon idée - une chose presque impensable dans les réalités actuelles, qui impliquent rapports quotidiens sur le travail effectué pendant la journée. Le processus de perfectionnement du programme a pris au total pas moins d'un an environ, mais même après cela, le résultat pouvait difficilement être qualifié de complètement réussi - trop de concepts différents ont été initialement définis qui n'étaient pas tout à fait clairs pour la mise en œuvre : des éléments facultatifs qui peuvent être ignoré ; visualisation avant des éléments (dans le but de remplacer les éléments précédents dans les résultats de recherche) ; même notre propre tentative d'implémenter quelque chose comme des expressions régulières (qui ont une syntaxe unique). Je dois dire qu'avant cela, j'avais quelque peu abandonné la programmation (pendant environ 8 ans, sinon plus), donc la nouvelle opportunité d'appliquer mes compétences à une tâche intéressante et nécessaire a complètement captivé mon attention. Il n'est pas surprenant que le code source résultant - en l'absence de toute approche claire de sa conception de ma part - soit assez rapidement devenu un méli-mélo inimaginable de morceaux disparates en langage C avec quelques éléments de C++ et des aspects de programmation visuelle (au départ, il Il a été décidé d'utiliser un système de conception tel que Borland C++ Builder - "presque Delphi, mais en C"). Cependant, tout cela a finalement porté ses fruits en automatisant les activités quotidiennes de notre bibliothèque.

Parallèlement, j'ai décidé, au cas où, de suivre des cours pour former des développeurs de logiciels professionnels. Je ne sais pas s'il est réellement possible d'apprendre « à être programmeur » là-bas, mais compte tenu des compétences que j'avais déjà à cette époque, j'ai pu maîtriser dans une certaine mesure des technologies qui étaient plus pertinentes à cette époque, comme comme C#, Visual Studio pour le développement sous .NET, ainsi que certaines technologies liées à Java, HTML et SQL. L'ensemble de la formation a duré au total deux ans et a servi de point de départ à un autre de mes projets, qui s'est finalement étalé sur plusieurs années - mais il s'agit d'un sujet pour une publication distincte. Ici, il conviendrait seulement de noter que j'ai tenté d'adapter les développements que j'avais déjà sur le projet décrit pour créer une application de fenêtre à part entière en C# et WinForms qui implémente les fonctionnalités nécessaires et l'utilise comme base pour le projet de diplôme à venir.
Au fil du temps, cette idée a commencé à me paraître digne d'être exprimée lors de conférences annuelles telles que la participation de représentants de diverses bibliothèques telles que « LIBKOM » et « CRIMEA ». L’idée, oui, mais pas ma mise en œuvre à ce moment-là. Ensuite, j'espérais aussi que quelqu'un le réécrirait en utilisant des approches plus compétentes. D'une manière ou d'une autre, en 2013, j'ai décidé de rédiger un rapport sur mes travaux préliminaires et de l'envoyer au comité d'organisation de la conférence avec une demande de subvention pour participer à la conférence. À ma grande surprise, ma candidature a été approuvée et j'ai commencé à apporter quelques améliorations au projet afin de le préparer pour sa présentation à la conférence.

À cette époque, le projet avait déjà reçu un nouveau nom BIRMA et avait acquis diverses capacités supplémentaires (pas tellement entièrement mises en œuvre, mais plutôt supposées) - tous les détails peuvent être trouvés dans mon rapport.

Pour être honnête, il était difficile de qualifier BIRMA 2013 de complet ; Franchement, c’était un engin très hacky, fabriqué à la hâte. En termes de code, il n'y a pratiquement eu aucune innovation particulière, à l'exception d'une tentative plutôt impuissante de créer une sorte de syntaxe unifiée pour l'analyseur, rappelant en apparence le langage de formatage IRBIS 64 (et en fait aussi le système ISIS - avec des parenthèses comme structures cycliques ; pourquoi à l'époque, je pensais que ça avait l'air plutôt cool). L'analyseur est tombé désespérément sur ces cercles de parenthèses du type approprié (puisque les parenthèses remplissaient également un autre rôle, à savoir qu'elles marquaient des structures facultatives lors de l'analyse qui pouvaient être ignorées). Je renvoie à nouveau plus en détail tous ceux qui souhaitent se familiariser avec la syntaxe alors difficile à imaginer et injustifiée de BIRMA à mon rapport de l'époque.

De manière générale, à part me débattre avec mon propre analyseur, je n'ai plus rien à dire concernant le code de cette version - à part la conversion inverse des sources existantes en C++ tout en préservant certaines fonctionnalités typiques du code .NET (pour être honnête, c'est difficile à comprendre, ce qui m'a poussé exactement à tout reculer - probablement une peur stupide de garder mes codes sources secrets, comme s'il s'agissait de quelque chose d'équivalent à la recette secrète de Coca-Cola).

Peut-être que cette décision stupide est aussi à l'origine des difficultés à coupler la bibliothèque DLL résultante avec l'interface existante d'un poste de travail fait maison pour saisir des données dans un catalogue électronique (oui, je n'ai pas mentionné un autre fait important : désormais, tous le code du « moteur » BIRMA était comme prévu, il est séparé de la partie interface et packagé dans la DLL appropriée). Pourquoi il était nécessaire d'écrire à ces fins un poste de travail séparé, qui, de toute façon, dans son apparence et sa méthode d'interaction avec l'utilisateur, copiait sans vergogne le même poste de travail «Catalogizer» du système IRBIS 64 - c'est une question distincte. En bref : cela a donné la solidité nécessaire à mes développements d'alors pour mon projet de fin d'études (sinon, le moteur d'analyse indigeste à lui seul n'était pas suffisant). De plus, j'ai ensuite rencontré quelques difficultés pour implémenter l'interface du poste Cataloger avec mes propres modules, implémentés à la fois en C++ et C#, et accéder directement à mon moteur.

En général, curieusement, c'est ce prototype plutôt maladroit du futur BIRMA.NET qui était destiné à devenir mon « bête de somme » pour les quatre prochaines années. On ne peut pas dire que pendant cette période, je n'ai pas au moins essayé de trouver les moyens de mettre en œuvre une idée nouvelle et plus complète d'une idée de longue date. Entre autres innovations, il aurait déjà dû y avoir des séquences cycliques imbriquées qui auraient pu inclure des éléments optionnels - c'est ainsi que j'allais donner vie à l'idée de​​modèles universels pour les descriptions bibliographiques des publications et diverses autres choses intéressantes. Cependant, dans mes activités pratiques à cette époque, tout cela était peu demandé, et la mise en œuvre que j'avais à cette époque était tout à fait suffisante pour saisir les tables des matières. De plus, le vecteur de développement de notre bibliothèque a commencé à s'écarter de plus en plus vers la numérisation des archives muséales, le reportage et d'autres activités de peu d'intérêt pour moi, ce qui m'a finalement obligé à la quitter définitivement, laissant la place à ceux qui le voudraient. soyez plus satisfait de tout cela.

Paradoxalement, c'est après ces événements dramatiques que le projet BIRMA, qui présentait déjà à cette époque tous les traits caractéristiques d'un projet de construction typique à long terme, semble commencer à prendre sa nouvelle vie tant attendue ! J'avais plus de temps libre pour des pensées vaines, j'ai recommencé à parcourir le World Wide Web à la recherche de quelque chose de similaire (heureusement, maintenant je pouvais déjà deviner qu'il fallait chercher tout cela non pas n'importe où, mais sur GitHub), et quelque part dans Au au début de cette année, je suis finalement tombé sur un produit correspondant de la célèbre société Salesforce sous le nom insignifiant Gorpe. À lui seul, il pourrait faire presque tout ce dont j'avais besoin d'un tel moteur d'analyse - à savoir isoler intelligemment des fragments individuels d'un texte arbitraire mais clairement structuré, tout en disposant d'une interface assez conviviale pour l'utilisateur final, comprenant des essences compréhensibles telles que un modèle, un modèle et une occurrence, et en même temps en utilisant la syntaxe familière des expressions régulières, qui devient incomparablement plus lisible en raison de la division en groupes sémantiques désignés pour l'analyse.

En général, j'ai décidé que c'était celui-là Gorpe (Je me demande ce que signifie ce nom ? Peut-être une sorte d’« analyseur régulier à orientation générale » ?) – exactement ce que je cherchais depuis longtemps. Certes, sa mise en œuvre immédiate pour mes propres besoins posait un tel problème que ce moteur nécessitait un respect trop strict de la séquence structurelle du texte source. Pour certains rapports tels que les fichiers journaux (c'est-à-dire qu'ils ont été placés par les développeurs comme exemples clairs d'utilisation du projet), cela est tout à fait approprié, mais pour les mêmes textes de tables des matières numérisées, c'est peu probable. Après tout, la même page avec une table des matières peut commencer par les mots « Table des matières », « Contenu » et toute autre description préliminaire que nous n'avons pas besoin de placer dans les résultats de l'analyse envisagée (et de les couper manuellement chaque fois est également gênant). De plus, entre les éléments répétitifs individuels, tels que le nom de l'auteur, le titre et le numéro de page, la page peut contenir une certaine quantité de déchets (par exemple, des dessins, et simplement des caractères aléatoires), qu'il serait également bien de pouvoir couper. Cependant, le dernier aspect n'était pas encore aussi important, mais en raison du premier, l'implémentation existante ne pouvait pas commencer à rechercher les structures nécessaires dans le texte à partir d'un certain endroit, mais au lieu de cela, elle les traitait simplement depuis le début, ne trouvait pas la j'y ai spécifié des modèles et... j'ai mis fin à mon travail. De toute évidence, quelques ajustements étaient nécessaires pour laisser au moins un peu d'espace entre les structures répétitives, et cela m'a remis au travail.

Un autre problème était que le projet lui-même était implémenté en Java, et si je prévoyais à l'avenir d'implémenter des moyens d'interfacer cette technologie avec des applications familières pour saisir des données dans des bases de données existantes (telles que le « Catalogueur » d'Irbis), alors au moins Au moins faites-le en C# et .NET. Ce n’est pas que Java en soi soit un mauvais langage – je l’ai même utilisé une fois pour implémenter une application fenêtre intéressante qui implémentait les fonctionnalités d’une calculatrice programmable domestique (dans le cadre d’un projet de cours). Et en termes de syntaxe, il est très similaire au même do dièse. Eh bien, ce n'est qu'un plus : plus il me sera facile de finaliser un projet existant. Cependant, je ne voulais pas replonger dans ce monde plutôt inhabituel des technologies Java de fenêtre (ou plutôt de bureau) - après tout, le langage lui-même n'était pas « conçu » pour un tel usage, et je n'avais pas du tout envie de répéter l'expérience précédente. C'est peut-être précisément parce que C#, associé à WinForms, est beaucoup plus proche de Delphi, avec lequel beaucoup d'entre nous ont commencé. Heureusement, la solution nécessaire a été trouvée assez rapidement - sous la forme du projet IKVM.NET, ce qui facilite la traduction de programmes Java existants en code .NET géré. Certes, le projet lui-même avait déjà été abandonné par les auteurs à cette époque, mais sa dernière mise en œuvre m'a permis de mener à bien avec succès les actions nécessaires pour les textes sources. Gorpe.

J'ai donc apporté toutes les modifications nécessaires et assemblé le tout dans une DLL du type approprié, qui pourrait facilement être « récupérée » par n'importe quel projet pour le .NET Framework créé dans Visual Studio. En attendant, j'ai créé un autre calque pour une présentation pratique des résultats renvoyés Gorpe, sous la forme de structures de données correspondantes qu'il serait pratique de traiter dans une vue tabulaire (en prenant comme base à la fois les lignes et les colonnes ; à la fois les clés du dictionnaire et les index numériques). Eh bien, les utilitaires eux-mêmes nécessaires au traitement et à l'affichage des résultats ont été écrits assez rapidement.

De plus, le processus d'adaptation des modèles pour le nouveau moteur afin de lui apprendre à analyser des échantillons existants de textes numérisés de tables des matières n'a pas entraîné de complications particulières. En fait, je n’ai même pas eu besoin de me référer à mes modèles précédents : j’ai simplement créé tous les modèles nécessaires à partir de zéro. De plus, si les modèles conçus pour fonctionner avec la version précédente du système fixaient un cadre assez étroit pour les textes pouvant être correctement analysés avec leur aide, le nouveau moteur permettait déjà de développer des modèles assez universels adaptés à plusieurs types de balisage à une fois. J'ai même essayé d'écrire une sorte de modèle complet pour n'importe quel texte de table des matières arbitraire, même si, bien sûr, même avec toutes les nouvelles possibilités qui s'ouvrent à moi, y compris, en particulier, la capacité limitée à implémenter les mêmes séquences répétitives imbriquées ( comme par exemple les noms et initiales de plusieurs auteurs à la suite), cela s'est avéré être une utopie.

Peut-être qu'à l'avenir, il sera possible de mettre en œuvre un certain concept de méta-modèles, qui pourront vérifier la conformité du texte source avec plusieurs des modèles disponibles à la fois, puis, en fonction des résultats obtenus, sélectionner le le plus approprié, en utilisant une sorte d’algorithme intelligent. Mais maintenant, j'étais plus préoccupé par une autre question. Un analyseur comme Gorpe, malgré toute sa polyvalence et les modifications que j'ai apportées, il était toujours intrinsèquement incapable de faire une chose apparemment simple que mon analyseur auto-écrit était capable de faire dès la toute première version. A savoir : il avait la capacité de trouver et d'extraire du texte source tous les fragments qui correspondent au masque spécifié dans le modèle utilisé au bon endroit, sans s'intéresser du tout à ce que le texte donné contient dans les espaces entre ces fragments. Jusqu'à présent, je n'ai que légèrement amélioré le nouveau moteur, lui permettant de rechercher toutes les nouvelles répétitions possibles d'une séquence donnée de tels masques à partir de la position actuelle, laissant la possibilité de la présence dans le texte d'ensembles de caractères arbitraires complètement disparu dans l'analyse, enfermé entre les structures répétitives détectées. Cependant, cela ne permettait pas de définir le masque suivant quels que soient les résultats de la recherche du fragment précédent à l'aide du masque correspondant : la rigueur de la structure du texte décrite ne laissait toujours pas de place à des inclusions arbitraires de caractères irréguliers.

Et si pour les exemples de tables des matières que j'ai rencontrés, ce problème ne semblait pas encore si grave, alors lorsque l'on essaie d'appliquer un nouveau mécanisme d'analyse à une tâche similaire d'analyse du contenu d'un site Web (c'est-à-dire la même analyse), son les limites sont là, elles sont apparues avec toute leur évidence. Après tout, il est assez simple de définir les masques nécessaires pour les fragments de balisage Web, entre lesquels doivent se trouver les données que nous recherchons (qui doivent être extraites), mais comment pouvons-nous forcer l'analyseur à passer immédiatement au suivant ? fragment similaire, malgré toutes les balises et attributs HTML possibles qui peuvent être placés dans les espaces entre eux ?

Après avoir réfléchi un peu, j'ai décidé d'introduire quelques modèles de service (%all_before) и (%all_after), dans le but évident de garantir que tout ce qui peut être contenu dans le texte source est ignoré avant tout modèle (masque) qui les suit. De plus, si (%all_before) simplement ignoré toutes ces inclusions arbitraires, alors (%all_after), au contraire, permettait de les ajouter au fragment souhaité après avoir quitté le fragment précédent. Cela semble assez simple, mais pour implémenter ce concept, j'ai dû parcourir à nouveau les sources de gorp pour apporter les modifications nécessaires afin de ne pas casser la logique déjà implémentée. En fin de compte, nous avons réussi à le faire (même si même la toute première implémentation, bien que très boguée, de mon analyseur a été écrite, et encore plus rapidement - en quelques semaines). Désormais, le système prend une forme véritablement universelle – pas moins de 12 ans après les premières tentatives pour le faire fonctionner.

Bien entendu, ce n’est pas la fin de nos rêves. Vous pouvez également réécrire complètement l'analyseur de modèle gorp en C#, en utilisant l'une des bibliothèques disponibles pour implémenter une grammaire gratuite. Je pense que le code devrait être considérablement simplifié, ce qui nous permettra de nous débarrasser de l'héritage sous la forme de sources Java existantes. Mais avec le type de moteur existant, il est également tout à fait possible de faire diverses choses intéressantes, notamment tenter d'implémenter les méta-modèles que j'ai déjà évoqués, sans oublier d'analyser diverses données provenant de divers sites Web (cependant, je n'exclus pas que les outils logiciels spécialisés existants sont plus adaptés à cela – je n’ai tout simplement pas encore eu l’expérience appropriée pour les utiliser).

D'ailleurs, cet été, j'ai déjà reçu une invitation par email d'une entreprise qui utilise les technologies Salesforce (le développeur de l'original Gorpe), passer un entretien pour un travail ultérieur à Riga. Malheureusement, pour le moment, je ne suis pas prêt à de tels redéploiements.

Si ce matériel suscite un certain intérêt, alors dans la deuxième partie j'essaierai de décrire plus en détail la technologie de compilation puis d'analyse des modèles en utilisant l'exemple d'implémentation utilisé dans Salesforce Gorpe (mes propres ajouts, à l'exception de quelques mots de fonction déjà décrits, n'apportent pratiquement aucune modification à la syntaxe du modèle lui-même, donc presque toute la documentation du système d'origine Gorpe Convient également à ma version).

Source: habr.com

Ajouter un commentaire