قصة مشروع صغير مدته اثني عشر عامًا (حول BIRMA.NET لأول مرة وبصراحة مباشرة)

يمكن اعتبار ولادة هذا المشروع فكرة صغيرة جاءت لي في مكان ما في نهاية عام 2007، والتي كان من المقرر أن تجد شكلها النهائي بعد 12 عامًا فقط (في هذا الوقت - بالطبع، على الرغم من أن التنفيذ الحالي، وفقًا للمؤلف، مرضية للغاية).

بدأ كل شيء عندما لفتت الانتباه، أثناء قيامي بواجباتي الرسمية في المكتبة، إلى حقيقة أن عملية إدخال البيانات من النص الممسوح ضوئيًا لجداول محتويات منشورات الكتب (والموسيقى) في قاعدة البيانات الحالية، على ما يبدو، يمكن تبسيطها وأتمتتها بشكل كبير، مع الاستفادة من خاصية الانتظام والتكرار لجميع البيانات المطلوبة للإدخال، مثل اسم مؤلف المقال (إذا كنا نتحدث عن مجموعة من المقالات)، وعنوان المقال المقالة (أو العنوان الفرعي المنعكس في جدول المحتويات) ورقم الصفحة لعنصر جدول المحتويات الحالي. في البداية، كنت مقتنعًا عمليًا بأن النظام المناسب لتنفيذ هذه المهمة يمكن العثور عليه بسهولة على الإنترنت. عندما كان سبب بعض المفاجأة هو أنني لم أتمكن من العثور على مثل هذا المشروع، قررت أن أحاول تنفيذه بمفردي.

بعد وقت قصير إلى حد ما، بدأ النموذج الأولي الأول في العمل، والذي بدأت استخدامه على الفور في أنشطتي اليومية، وفي نفس الوقت قمت بتصحيحه على جميع الأمثلة التي وصلت إلى يدي. لحسن الحظ، في مكان عملي المعتاد، حيث لم أكن مبرمجًا بأي حال من الأحوال، ما زلت أفلت من "فترات التوقف" الواضحة في عملي، والتي كنت خلالها أقوم بتصحيح الأخطاء بشكل مكثف من بنات أفكاري - وهو أمر لا يمكن تصوره تقريبًا في الواقع الحالي، والذي يعني ضمنيًا تقارير يومية عن الأعمال المنجزة خلال اليوم. استغرقت عملية صقل البرنامج ما لا يقل عن عام تقريبًا، ولكن حتى بعد ذلك لا يمكن وصف النتيجة بأنها ناجحة تمامًا - فقد تم في البداية وضع العديد من المفاهيم المختلفة التي لم تكن واضحة تمامًا للتنفيذ: العناصر الاختيارية التي يمكنها يتم تخطيها؛ العرض الأمامي للعناصر (لغرض استبدال العناصر السابقة في نتائج البحث)؛ حتى محاولتنا الخاصة لتنفيذ شيء مثل التعبيرات العادية (التي لها بناء جملة فريد). يجب أن أقول أنه قبل ذلك كنت قد تخليت عن البرمجة إلى حد ما (لمدة 8 سنوات تقريبًا، إن لم يكن أكثر)، لذا فإن الفرصة الجديدة لتطبيق مهاراتي في مهمة مثيرة للاهتمام وضرورية لفتت انتباهي تمامًا. ليس من المستغرب أن الكود المصدري الناتج - في غياب أي نهج واضح لتصميمه من جهتي - أصبح بسرعة كبيرة مزيجًا لا يمكن تصوره من القطع المتباينة في لغة C مع بعض عناصر C++ وجوانب البرمجة المرئية (في البداية كانت تقرر استخدام نظام تصميم مثل Borland C++ Builder - "تقريبًا دلفي، ولكن في C"). ومع ذلك، كل هذا أتى بثماره في نهاية المطاف في أتمتة الأنشطة اليومية لمكتبتنا.

في الوقت نفسه، قررت، تحسبًا، أن آخذ دورات لتدريب مطوري البرامج المحترفين. لا أعرف ما إذا كان من الممكن حقًا أن أتعلم "أن أكون مبرمجًا" من الصفر هناك، ولكن مع الأخذ في الاعتبار المهارات التي كنت أمتلكها بالفعل في ذلك الوقت، فقد تمكنت إلى حد ما من إتقان التقنيات التي كانت أكثر أهمية في ذلك الوقت، مثل مثل C#، وVisual Studio للتطوير ضمن .NET، بالإضافة إلى بعض التقنيات المتعلقة بـ Java وHTML وSQL. استغرق التدريب بأكمله عامين، وكان بمثابة نقطة انطلاق لمشروع آخر لي، والذي امتد في النهاية على مدى عدة سنوات - ولكن هذا موضوع لمنشور منفصل. سيكون من المناسب هنا ملاحظة أنني قمت بمحاولة تكييف التطورات التي أجريتها بالفعل في المشروع الموصوف لإنشاء تطبيق نافذة كامل في C# وWinForms ينفذ الوظائف الضرورية، ويستخدمه كأساس لـ مشروع الدبلوم القادم.
بمرور الوقت، بدأت هذه الفكرة تبدو لي جديرة بالتعبير عنها في مثل هذه المؤتمرات السنوية بمشاركة ممثلي المكتبات المختلفة مثل "LIBKOM" و"CRIMEA". الفكرة نعم، ولكن ليس تطبيقي لها في ذلك الوقت. ثم تمنيت أيضًا أن يقوم شخص ما بإعادة كتابتها باستخدام أساليب أكثر كفاءة. بطريقة أو بأخرى، قررت بحلول عام 2013 أن أكتب تقريرًا عن أعمالي الأولية وأرسله إلى اللجنة المنظمة للمؤتمر مع طلب الحصول على منحة للمشاركة في المؤتمر. ولدهشتي بعض الشيء، تمت الموافقة على طلبي، وبدأت في إجراء بعض التحسينات على المشروع لإعداده للعرض في المؤتمر.

بحلول ذلك الوقت، كان المشروع قد تلقى بالفعل اسمًا جديدًا لـ BIRMA، واكتسب العديد من القدرات الإضافية (التي لم يتم تنفيذها بالكامل، بل المفترضة) - كل التفاصيل تجدونها في تقريري.

لأكون صادقًا، كان من الصعب وصف BIRMA 2013 بأنه شيء مكتمل؛ بصراحة، لقد كانت حرفة متقنة للغاية تم صنعها على عجل. فيما يتعلق بالكود، لم تكن هناك أي ابتكارات خاصة على الإطلاق، باستثناء محاولة عاجزة إلى حد ما لإنشاء نوع من بناء الجملة الموحد للمحلل اللغوي، في المظهر الذي يذكرنا بلغة التنسيق IRBIS 64 (وفي الواقع، أيضًا نظام إيزيس - مع الأقواس كهياكل دورية؛ لماذا في ذلك الوقت اعتقدت أنها تبدو رائعة جدًا). عثر المحلل اللغوي بشكل يائس على دوائر الأقواس من النوع المناسب (نظرًا لأن الأقواس تؤدي أيضًا دورًا آخر، أي أنها حددت الهياكل الاختيارية التي يمكن تخطيها أثناء التحليل). أحيل مرة أخرى كل من يريد التعرف على بناء جملة BIRMA الذي يصعب تخيله وغير المبرر بمزيد من التفصيل إلى تقريري في ذلك الوقت.

بشكل عام، وبصرف النظر عن معاناتي مع المحلل اللغوي الخاص بي، ليس لدي ما أقوله بخصوص كود هذا الإصدار - باستثناء التحويل العكسي للمصادر الموجودة إلى C++ مع الحفاظ على بعض الميزات النموذجية لكود .NET (لأكون صادقًا، إنه يصعب فهمه، ما الذي دفعني بالضبط إلى نقل كل شيء مرة أخرى - ربما بعض الخوف الغبي من الحفاظ على سرية رموز المصدر الخاصة بي، كما لو كان شيئًا يعادل الوصفة السرية لشركة Coca-Cola).

ولعل هذا القرار الغبي يكمن أيضًا في سبب الصعوبات في إقران مكتبة DLL الناتجة بالواجهة الحالية لمحطة عمل محلية الصنع لإدخال البيانات في الكتالوج الإلكتروني (نعم، لم أذكر حقيقة مهمة أخرى: من الآن فصاعدًا، كل شيء كان رمز "محرك" BIRMA كما هو متوقع، وتم فصله عن جزء الواجهة وتعبئته في ملف DLL المناسب). لماذا كان من الضروري كتابة محطة عمل منفصلة لهذه الأغراض، والتي على أي حال، في مظهرها وطريقة التفاعل مع المستخدم، نسخت بلا خجل نفس محطة العمل "Catalogizer" لنظام IRBIS 64 - هذا سؤال منفصل. باختصار: لقد أعطت الصلابة اللازمة لتطوراتي آنذاك لمشروع التخرج الخاص بي (وإلا فإن المحرك المحلل اللغوي غير القابل للهضم وحده لم يكن كافيًا إلى حد ما). بالإضافة إلى ذلك، واجهت بعد ذلك بعض الصعوبات في تنفيذ واجهة محطة عمل Cataloger مع الوحدات النمطية الخاصة بي، والتي تم تنفيذها في كل من C++ وC#، وفي الوصول مباشرة إلى المحرك الخاص بي.

بشكل عام، ومن الغريب أن هذا النموذج الأولي الأخرق إلى حد ما لـ BIRMA.NET المستقبلي هو الذي كان من المقرر أن يصبح "عمود العمل" الخاص بي على مدار السنوات الأربع القادمة. لا يمكن القول أنه خلال هذا الوقت لم أحاول على الأقل إيجاد طرق لتنفيذ جديد أكثر اكتمالاً لفكرة طويلة الأمد. من بين الابتكارات الأخرى، كان من المفترض أن تكون هناك بالفعل تسلسلات دورية متداخلة يمكن أن تتضمن عناصر اختيارية - هكذا كنت سأقوم بإحياء فكرة القوالب العالمية للأوصاف الببليوغرافية للمنشورات وأشياء أخرى مختلفة مثيرة للاهتمام. ومع ذلك، في أنشطتي العملية في ذلك الوقت، كان الطلب على كل هذا قليلًا، وكان التنفيذ الذي قمت به في ذلك الوقت كافيًا تمامًا لإدخال جداول المحتويات. بالإضافة إلى ذلك، بدأ اتجاه تطوير مكتبتنا ينحرف أكثر فأكثر نحو رقمنة أرشيفات المتاحف، وإعداد التقارير وغيرها من الأنشطة التي لا تهمني كثيرًا، الأمر الذي أجبرني في النهاية على تركها أخيرًا، وإفساح المجال لأولئك الذين يريدون ذلك. كن أكثر سعادة مع كل هذا.

ومن المفارقات أنه بعد هذه الأحداث الدرامية، بدا أن مشروع BIRMA، الذي كان يمتلك في ذلك الوقت جميع السمات المميزة لمشروع بناء نموذجي طويل الأجل، قد بدأ في اكتساب حياته الجديدة التي طال انتظارها! كان لدي المزيد من وقت الفراغ للأفكار الخاملة، بدأت مرة أخرى في تمشيط شبكة الويب العالمية بحثًا عن شيء مماثل (لحسن الحظ، الآن يمكنني بالفعل تخمين كل هذا للبحث عنه ليس فقط في أي مكان، ولكن على GitHub)، وفي مكان ما في في في بداية هذا العام، عثرت أخيرًا على منتج مماثل من شركة Salesforce المعروفة تحت اسم غير مهم غورب. في حد ذاته، يمكن أن يفعل كل ما أحتاجه تقريبًا من هذا المحرك المحلل اللغوي - أي عزل الأجزاء الفردية بذكاء من النص التعسفي ولكن المنظم بشكل واضح، مع وجود واجهة سهلة الاستخدام إلى حد ما للمستخدم النهائي، بما في ذلك هذه الجواهر المفهومة، مثل نمط وقالب وحدث، وفي نفس الوقت استخدام بناء الجملة المألوف للتعبيرات العادية، والذي يصبح أكثر قابلية للقراءة بشكل لا يضاهى بسبب التقسيم إلى مجموعات دلالية معينة للتحليل.

بشكل عام، قررت أن هذا هو واحد غورب (أتساءل ماذا يعني هذا الاسم؟ ربما نوع من "المحلل العادي ذو التوجه العام"؟) - بالضبط ما كنت أبحث عنه لفترة طويلة. صحيح أن تنفيذه الفوري لاحتياجاتي الخاصة واجه مشكلة كبيرة لدرجة أن هذا المحرك يتطلب التزامًا صارمًا للغاية بالتسلسل الهيكلي للنص المصدر. بالنسبة لبعض التقارير مثل ملفات السجل (أي، تم وضعها من قبل المطورين كأمثلة واضحة لاستخدام المشروع)، يعد هذا مناسبًا تمامًا، ولكن بالنسبة لنفس نصوص جداول المحتويات الممسوحة ضوئيًا، فمن غير المحتمل. بعد كل شيء، يمكن أن تبدأ نفس الصفحة التي تحتوي على جدول المحتويات بالكلمات "جدول المحتويات" و"المحتويات" وأي أوصاف أولية أخرى لا نحتاج إلى وضعها في نتائج التحليل المقصود (وقصها يدويًا في كل مرة يكون الأمر غير مريح أيضًا). بالإضافة إلى ذلك، بين العناصر المتكررة الفردية، مثل اسم المؤلف والعنوان ورقم الصفحة، قد تحتوي الصفحة على قدر معين من البيانات المهملة (على سبيل المثال، الرسومات والأحرف العشوائية فقط)، والتي سيكون من الجيد أيضًا أن تكون قادرًا على ذلك قطع. ومع ذلك، فإن الجانب الأخير لم يكن مهمًا بعد، ولكن نظرًا للجانب الأول، لم يتمكن التنفيذ الحالي من البدء في البحث عن الهياكل الضرورية في النص من مكان معين، ولكن بدلاً من ذلك قام ببساطة بمعالجته من البداية، ولم يجد الأنماط المحددة هناك و... أنهيت وظيفتي. من الواضح أن هناك حاجة إلى بعض التغيير والتبديل لإتاحة بعض المساحة على الأقل بين الهياكل المتكررة، وهذا ما أعادني إلى العمل.

كانت المشكلة الأخرى هي أن المشروع نفسه تم تنفيذه في Java، وإذا كنت أخطط في المستقبل لتنفيذ بعض وسائل ربط هذه التكنولوجيا مع التطبيقات المألوفة لإدخال البيانات في قواعد البيانات الموجودة (مثل "Cataloguer" من Irbis)، فعلى الأقل قم بذلك في C# و.NET. لا يعني ذلك أن Java في حد ذاتها لغة سيئة - بل إنني استخدمتها ذات مرة لتنفيذ تطبيق نافذة مثير للاهتمام يطبق وظيفة الآلة الحاسبة المحلية القابلة للبرمجة (كجزء من مشروع الدورة التدريبية). ومن حيث بناء الجملة فهو مشابه جدًا لنفس C-sharp. حسنًا، هذه مجرد ميزة إضافية: سيكون من الأسهل بالنسبة لي إنهاء مشروع حالي. ومع ذلك، لم أرغب في الانغماس مرة أخرى في هذا العالم غير العادي إلى حد ما من تقنيات جافا (أو بالأحرى سطح المكتب) - بعد كل شيء، لم تكن اللغة نفسها "مصممة" لمثل هذا الاستخدام، ولم أرغب على الإطلاق في تكرار التجربة السابقة. ربما يكون السبب على وجه التحديد هو أن C# بالتزامن مع WinForms أقرب بكثير إلى دلفي، التي بدأ بها الكثير منا ذات يوم. ولحسن الحظ، تم العثور على الحل اللازم بسرعة كبيرة - في شكل المشروع IKVM.NET، مما يجعل من السهل ترجمة برامج Java الموجودة إلى كود .NET مُدار. صحيح أن المشروع نفسه قد تم التخلي عنه بالفعل من قبل المؤلفين بحلول ذلك الوقت، لكن تنفيذه الأخير سمح لي بتنفيذ الإجراءات اللازمة للنصوص المصدر بنجاح كبير غورب.

لذلك قمت بإجراء كافة التغييرات اللازمة وقمت بتجميعها كلها في ملف DLL من النوع المناسب، والذي يمكن بسهولة "التقاطه" بواسطة أي مشروع لـ .NET Framework تم إنشاؤه في Visual Studio. في هذه الأثناء، قمت بإنشاء طبقة أخرى للعرض الملائم للنتائج التي تم إرجاعها غورب، في شكل هياكل بيانات مقابلة تكون ملائمة للمعالجة في عرض الجدول (مع أخذ الصفوف والأعمدة كأساس؛ ومفاتيح القاموس والفهارس الرقمية). حسنًا، تمت كتابة الأدوات المساعدة اللازمة لمعالجة النتائج وعرضها بسرعة كبيرة.

كما أن عملية تكييف القوالب للمحرك الجديد لتعليمه تحليل العينات الموجودة من النصوص الممسوحة ضوئيًا لجداول المحتويات لم تسبب أي تعقيدات خاصة. في الواقع، لم أضطر حتى إلى الرجوع إلى قوالبي السابقة على الإطلاق: لقد قمت ببساطة بإنشاء جميع النماذج الضرورية من الصفر. علاوة على ذلك، إذا كانت القوالب المصممة للعمل مع الإصدار السابق من النظام تضع إطارًا ضيقًا إلى حد ما للنصوص التي يمكن تحليلها بشكل صحيح بمساعدتها، فقد جعل المحرك الجديد من الممكن بالفعل تطوير قوالب عالمية إلى حد ما مناسبة لعدة أنواع من العلامات على مرة واحدة. حتى أنني حاولت كتابة نوع من القالب الشامل لأي نص عشوائي في جدول المحتويات، على الرغم من أنه، بالطبع، حتى مع كل الاحتمالات الجديدة المفتوحة أمامي، بما في ذلك، على وجه الخصوص، القدرة المحدودة على تنفيذ نفس التسلسلات المتكررة المتداخلة ( مثل، على سبيل المثال، الألقاب والأحرف الأولى من العديد من المؤلفين على التوالي)، تبين أن هذه المدينة الفاضلة.

ربما سيكون من الممكن في المستقبل تنفيذ مفهوم معين للقوالب الوصفية، والتي ستكون قادرة على التحقق من النص المصدر للتأكد من امتثاله للعديد من القوالب المتاحة في وقت واحد، وبعد ذلك، وفقًا للنتائج التي تم الحصول عليها، حدد الأكثر ملاءمة، وذلك باستخدام نوع من الخوارزمية الذكية. ولكن الآن كنت أكثر قلقا بشأن سؤال آخر. محلل مثل غورب، على الرغم من تعدد استخداماته والتعديلات التي أجريتها، إلا أنه كان لا يزال غير قادر بطبيعته على القيام بشيء واحد يبدو بسيطًا كان المحلل اللغوي الذي كتبته بنفسي قادرًا على القيام به منذ الإصدار الأول. وهي: كان لديه القدرة على العثور على جميع الأجزاء المطابقة للقناع المحدد داخل القالب المستخدم في المكان المناسب واستخراجها من النص المصدر، في حين أنه لا يهتم على الإطلاق بما يحتويه النص المحدد في الفراغات بين هذه الأجزاء. حتى الآن، قمت فقط بتحسين المحرك الجديد بشكل طفيف، مما سمح له بالبحث عن جميع التكرارات الجديدة المحتملة لتسلسل معين من هذه الأقنعة من الموضع الحالي، مع ترك إمكانية وجود مجموعات من الأحرف التعسفية في النص والتي تم تغييرها بالكامل مجهول المصير في التحليل، محاطًا بين الهياكل المتكررة المكتشفة. ومع ذلك، فإن هذا لم يجعل من الممكن تعيين القناع التالي بغض النظر عن نتائج البحث عن الجزء السابق باستخدام القناع المقابل: إن صرامة بنية النص الموصوفة لا تزال لا تترك مجالًا للتضمين التعسفي للأحرف غير المنتظمة.

وإذا كانت هذه المشكلة بالنسبة لأمثلة جداول المحتويات التي صادفتها لا تبدو خطيرة جدًا بعد، فعند محاولة تطبيق آلية تحليل جديدة على مهمة مماثلة لتحليل محتويات موقع ويب (أي نفس التحليل)، القيود هنا ظهرت بكل وضوحها. بعد كل شيء، من السهل جدًا تعيين الأقنعة اللازمة لأجزاء ترميز الويب، حيث يجب وضع البيانات التي نبحث عنها (والتي يجب استخراجها)، ولكن كيف يمكننا إجبار المحلل اللغوي على الانتقال فورًا إلى التالي جزء مماثل، على الرغم من كل العلامات المحتملة وسمات HTML التي يمكن وضعها في المسافات بينهما؟

بعد التفكير قليلاً، قررت تقديم اثنين من أنماط الخدمة (%all_before) и (%all_after)، يخدم الغرض الواضح المتمثل في ضمان تخطي كل ما قد يكون موجودًا في النص المصدر قبل أي نمط (قناع) يتبعه. وعلاوة على ذلك، إذا (%all_before) لقد تجاهلت بكل بساطة كل هذه الإدراجات التعسفية (%all_after)على العكس من ذلك، سمح بإضافتها إلى الجزء المطلوب بعد الانتقال من الجزء السابق. يبدو الأمر بسيطًا للغاية، ولكن لتنفيذ هذا المفهوم، كان عليّ البحث في مصادر المجموعة مرة أخرى لإجراء التعديلات اللازمة حتى لا يتم كسر المنطق المطبق بالفعل. في النهاية، تمكنا من القيام بذلك (على الرغم من أنه حتى الأول، وإن كان عربات التي تجرها الدواب للغاية، تمت كتابة تنفيذ المحلل اللغوي الخاص بي، وحتى بشكل أسرع - في غضون أسبوعين). ومن الآن فصاعدا، اتخذ النظام شكلا عالميا حقا - بعد مرور ما لا يقل عن 12 عاما من المحاولات الأولى لجعله يؤدي وظيفته.

وبطبيعة الحال، هذه ليست نهاية أحلامنا. يمكنك أيضًا إعادة كتابة المحلل اللغوي لقالب Gorp بالكامل في لغة C#، باستخدام أي من المكتبات المتاحة لتنفيذ قواعد نحوية مجانية. أعتقد أنه يجب تبسيط التعليمات البرمجية بشكل كبير، وهذا سيسمح لنا بالتخلص من الإرث في شكل مصادر Java الموجودة. ولكن مع نوع المحرك الحالي، من الممكن أيضًا القيام بأشياء مختلفة مثيرة للاهتمام، بما في ذلك محاولة تنفيذ القوالب الوصفية التي ذكرتها بالفعل، ناهيك عن تحليل البيانات المختلفة من مواقع الويب المختلفة (ومع ذلك، لا أستبعد أن الأدوات البرمجية المتخصصة الموجودة هي أكثر ملاءمة لهذا - ولكنني لم أتمتع بالخبرة المناسبة لاستخدامها بعد).

بالمناسبة، لقد تلقيت بالفعل هذا الصيف دعوة عبر البريد الإلكتروني من شركة تستخدم تقنيات Salesforce (المطور الأصلي غورب)، اجتياز مقابلة للعمل اللاحق في ريغا. لسوء الحظ، في الوقت الحالي لست مستعدًا لعمليات إعادة الانتشار هذه.

إذا كانت هذه المادة تثير بعض الاهتمام، فسأحاول في الجزء الثاني أن أصف بمزيد من التفصيل تقنية تجميع القوالب وتحليلها لاحقًا باستخدام مثال التنفيذ المستخدم في Salesforce غورب (إضافاتي الخاصة، باستثناء بضع كلمات وظيفية تم وصفها بالفعل، لا تُجري أي تغييرات تقريبًا على بناء جملة القالب نفسه، لذا فإن جميع الوثائق الخاصة بالنظام الأصلي تقريبًا غورب مناسبة لنسختي أيضًا).

المصدر: www.habr.com

إضافة تعليق