Gorp.NET هي مكتبة جديدة لإنشاء قوالب قابلة للعكس لاستخراج البيانات من نص منظم ، بناءً على قاعدة كود Salesforce Gorp الحالية.في هذا المنشور ، سأتحدث قليلاً عن كيفية استخدام المكتبة لتحليل نص منظم يسمى
Gorp (أحد أمثلة الأدوات ، التي تسمى أحيانًا أنظمة إنشاء
قوالب قابلة للعكس ).
ما هو
قالب عكسها بشكل عام؟ افترض أن لدينا نظامًا معينًا يسمح لنا بإنشاء النص الذي نحتاجه استنادًا إلى البيانات الأولية التي حددناها وفقًا لقواعد صارمة تم تحديدها من خلال بناء جملة القوالب. الآن ، دعونا نتخيل مهمة متناقضة في المعنى - لدينا نص له بعض النزاهة الهيكلية التي يمكن تحقيقها باستخدام نظام يعتمد على القوالب من المثال السابق. هدفنا هو استخراج البيانات المصدر من هذا النص على أساسها. إذا حاولنا التوصل إلى بناء جملة معمم لحل هذه المشكلة ، تم توفيره للمحلل المقابل ، الذي يوزع نص الإدخال في عناصر منفصلة ، فسيكون هذا مثالًا على بناء الجملة لتطبيق مفهوم القوالب القابلة للعكس.
لماذا قررت الكتابة بالتحديد عن
Gorp ؟ والحقيقة هي أنني قررت أن أعتبر هذا النظام الخاص أساسًا لوضع اللمسات الأخيرة على مشروعي الخاص - يمكن العثور على تاريخ المشروع نفسه ، بما في ذلك بعض تفاصيل جميع التغييرات التي أجريتها على مشروع
Gorp الأصلي ،
في المقالة السابقة . سنركز هنا بالتحديد على الجزء الفني ، بما في ذلك فيما يتعلق باستخدام نسخة معدلة من المحرك. للراحة ، سأستمر في تسميته
Gorp.NET ، على الرغم من أنه في الواقع ليس إصدارًا من
Gorp لا يتم نقله إلى .NET ، ولكنه فقط نسخة مصقولة
ومكتملة منه ، كل ذلك في نفس Java. شيء آخر هو أن الوظيفة الإضافية الموجودة أعلى مكتبة
Gorp نفسها (في الإصدار الخاص بي) في شكل مكتبة DLL مدارة تسمى
BIRMA.NET تستخدم تجميعها الخاص -
Gorp.NET ، والذي يمكنك الحصول عليه بسهولة إذا قمت بتشغيل النص المصدر ( عنوان
مستودعه هو
https://github.com/S-presso/gorp/ ) من خلال الأداة المساعدة
IKVM.NET .
سألاحظ الآن أنه بالنسبة لجميع أنواع مهام استخراج البيانات من أي نص منظم ، فإن أدوات
Gorp.NET نفسها ستكون كافية بالنسبة
لك - على الأقل إذا كان لديك القليل من أوامر جافا أو على الأقل معرفة كيفية استدعاء طرق من وحدات Java الخارجية في مشاريعك على .NET Framework ، بالإضافة إلى تضمين أنواع مختلفة من مكتبات JVM القياسية هناك (لقد حققت ذلك من خلال نفس
IKVM.NET ، والذي أصبح لديه بالفعل حالة مشروع غير مدعوم). حسنًا ، وماذا ستفعل بعد ذلك مع البيانات المستخرجة - هذا ، كما يقولون ، هو عملك الشخصي.
يوفر Gorp و
Gorp.NET وحدهما إطار عمل مكشوف فقط. بعض الأعمال الأساسية لمزيد من المعالجة لجميع هذه البيانات تحتوي على
BIRMA.NET المذكورة أعلاه. لكن وصف وظيفة
BIRMA.NET في
حد ذاته هو بالفعل موضوع لمنشور منفصل (على الرغم من أنني تمكنت بالفعل من ذكر شيء في تقييمي السابق
والمقارنة التاريخية لتقنيات BIRMA ). هنا ، بالنظر إلى المستقبل ، سوف أسمح لنفسي ببيان جريء إلى حد ما مفاده أن التكنولوجيا المستخدمة لوصف القوالب العكسية المستخدمة في
Gorp.NET (وبالتالي ،
BIRMA.NET ) فريدة إلى حد ما بين الحرف الأخرى من هذا النوع (أقول " الحرف اليدوية "، لأن الشركات الكبيرة بطريقة ما لم أرها بعد في الترويج لأطرها الخاصة لهذه الأغراض - حسناً ، ربما فقط
Salesforce نفسها بتطبيقها الأصلي لـ
Gorp ).
من أجل الكشف الكامل عن المفهوم والجوانب التقنية التي يقوم عليها نظام وصف القالب المستخدم في Gorp ، أترك هنا رابطًا
للوثائق الأصلية باللغة الإنجليزية . كل ما هو مذكور في ذلك ، يمكنك التقدم بأمان فيما يتعلق
Gorp.NET . والآن سوف أخبركم قليلاً عن الجوهر.
لذا ، فإن وصف القالب هو نوع من المستندات النصية (ربما يتم تقديمها كسطر واحد كبير ، والذي يمكن تمريره إلى الطريقة المقابلة للمعالجة). وهو يتألف من ثلاثة أجزاء تحتوي على أوصاف متتابعة لأهم ثلاثة كيانات:
الأنماط والأنماط والعينات (المقتطفات).
كتلة المستوى الأدنى هنا هي
الأنماط - يمكن أن تتكون فقط من التعبيرات والإشارات العادية إلى الأنماط الأخرى. يشغل المستوى التالي من التسلسل الهرمي
قوالب ، والتي يحتوي وصفها أيضًا على روابط للأنماط ، والتي يمكن أيضًا تسميتها ، بالإضافة إلى تضمينات في شكل حرفية نصية ، وروابط للقوالب المتداخلة والمستخلصات. هناك أيضًا
أنماط بارامترية لن أتطرق إليها حاليًا (توجد في الوثائق المصدر أمثلة قليلة لاستخدامها). حسنًا ، أخيرًا ، هناك
نماذج تحدد قواعد نحوية محددة تربط
الأنماط المسماة بوقائع معينة من النص المصدر.
كما أفهمها ، كان الهدف الأصلي الذي حدده مُنشئو
Gorp هو
تحليل تسلسل البيانات الموجودة في ملفات التقارير (أو ملفات السجل). النظر في مثال بسيط لتطبيق معين للنظام.
لنفترض أن لدينا تقريرًا يحتوي على السطر التالي:
<86> 2015-05-12T20: 57: 53.302858 + 00: 00 10.1.11.141 RealSource: "10.10.5.3"
لنقم بإنشاء قالب مثال
لتحليله باستخدام أدوات
Gorp :
pattern %phrase \\S+
pattern %num \\d+\n
pattern %ts %phrase
pattern %ip %phrase
extract interm {
template <%num>$eventTimeStamp(%ts) $logAgent(%ip) RealSource: "$logSrcIp(%ip)"
}
لاحظ أنه يتم حذف كتلة تخصيص القالب هنا ، نظرًا لأن جميع القوالب الضرورية مدرجة بالفعل في التحديد النهائي. تتم تسمية جميع القوالب المستخدمة هنا ، ومحتوياتها مبينة بين قوسين بعد الاسم. نتيجة لذلك ، سيتم إنشاء مجموعة بيانات نصية بأسماء
eventTimeStamp و
logAgent و
logSrcIp .
سنقوم الآن بكتابة برنامج بسيط لاستخراج البيانات اللازمة. افترض أن القالب الذي أنشأناه موجود بالفعل في ملف يسمى
extractions.xtr .
import com.salesforce.gorp.DefinitionReader; import com.salesforce.gorp.ExtractionResult; import com.salesforce.gorp.Gorp;
مثال آخر على قالب تحليل بسيط:
# Patterns
pattern %num \d+
pattern %hostname [a-zA-Z0-9_\-\.]+
pattern %status \w+
# Templates
@endpoint $srcHost(%hostname): $srcPort(%num)
# Extraction
extract HostDefinition {
template @endpoint $status(%status)
}
حسنا ، أعتقد أن النقطة واضحة. لن يكون من الخطأ أيضًا ذكر أنه بالنسبة لطريقة
الاستخراج ، يوجد أيضًا تعريف بمعلمتين للإدخال ، الثاني له نوع منطقي. إذا قمت بتعيينها على
صواب ، فعند تنفيذها ، سوف تتكرر الطريقة على جميع مجموعات البيانات المحتملة - حتى تصادف مجموعة مناسبة (يمكنك أيضًا استبدال استدعاء الأسلوب بـ
extractSafe - بدون بالفعل المعلمة الثانية). الإعداد الافتراضي
خاطئ ، وقد "تقسم" الطريقة عند التناقض بين بيانات الإدخال والقالب المستخدم.
ألاحظ في الوقت نفسه أن
Gorp.NET قدم
أيضًا تطبيقًا موسعًا جديدًا لأسلوب
الاستخراج : يوجد الآن إصدار به
معلمتان تاليتان من النوع المنطقي. باستخدام مكالمة مختصرة إلى
طريقة العرض extractAllFound ، قمنا بتعيين كل منهما على true افتراضيًا. تمنحنا القيمة الإيجابية للمعلمة الثالثة مجالًا أكبر للتغيرات: من الآن فصاعدًا ، يمكننا تحليل النص مع أي تضمين من الأحرف التعسفية في الفترات الفاصلة بين العينات المرغوبة بالفعل المنظمة (التي تحتوي على مجموعات من البيانات المستخرجة).
لذا ، فقد حان الوقت للإجابة على السؤال: ما الذي يمكن أن يكون فريدًا في هذا التعديل للنسخة الأساسية من
Gorp ، إلى جانب امتداد طريقة الاستخراج؟
الحقيقة هي أنه عندما قمت قبل عدة سنوات بإنشاء نوع من أداتي الخاصة لاستخراج البيانات المطلوبة من النص (والتي كانت تستند أيضًا إلى معالجة قوالب معينة باستخدام بناء الجملة الخاصة بها) ، فقد عملت على مبادئ مختلفة قليلاً. الاختلاف الرئيسي بينهما عن النهج المطبق في
Gorp وجميع الأطر المشتقة هو أن كل عنصر نصي يتم استخلاصه تم تعيينه ببساطة عن طريق سرد حدوده اليمنى واليسرى (كل منها بدوره يمكن أن يكون إما جزءًا من العنصر نفسه ، أو ببساطة فصله عن كل النص اللاحق أو السابق). في الوقت نفسه ، في الواقع ، في الحالة العامة ، لم يتم تحليل بنية النص المصدر نفسه ، كما هو الحال في
Gorp ، ولكن تم تحديد
الأجزاء الضرورية فقط. أما بالنسبة لمحتوى النص المحاط بينهما ، فإنه لا يمكن أن يستسلم على الإطلاق لأي تحليل هيكلي (يمكن أن يكون مجموعات حروف غير متسقة).
هل من الممكن تحقيق تأثير مماثل في
Gorp ؟ في نسخته الأولية - ربما لا (صحح لي إذا كنت مخطئًا بشأن هذا). إذا كتبنا ببساطة تعبيرًا مثل
(. *) ، يتبعه على الفور قناع لتحديد الحد الأيسر للعنصر التالي الذي سيتم البحث فيه ، ثم باستخدام محدد "الجشع" ، سيتم التقاط النص التالي بالكامل. ولا يمكننا استخدام النظام الأساسي مع بناء الجملة "غير الجشع" في تطبيقات
Gorp الموجودة.
يتيح
لك Gorp.NET التحايل على هذه المشكلة بسلاسة عن طريق تقديم نوعين خاصين من الأنماط -
(٪ all_before) و
(٪ all_after) . أولها ، في الواقع ، هو بديل للإصدار "غير الجشع"
(. *) ، مناسب للاستخدام في تجميع القوالب الخاصة بك. بالنسبة لـ
(٪ all_after) ، فإنه يبحث أيضًا في النص المصدر حتى
الظهور الأول للجزء التالي من النموذج الموصوف - ولكنه يعتمد بالفعل على نتيجة بحث النموذج السابق. كل ما بينهما سوف يقع أيضًا في السلسلة الفرعية القابلة للاستخراج للعنصر الحالي. بمعنى ما
(٪ all_after) "ينظر إلى الخلف" ، و
(٪ all_before) ، على العكس من ذلك ، "يتطلع إلى الأمام". لاحظت أن
التماثل الفريد لـ
(٪ all_before) في الإصدار الأول من
BIRMA هو الحدود اليسرى المفقودة في وصف العنصر ، وكان مماثل لـ
(٪ all_after) ، على التوالي ، فراغًا بدلاً من الحد الأيمن. إذا لم يتم تعيين كلا الحدين عند وصف العنصر التالي ، فمن الواضح أن المحلل اللغوي يلتقط كل النص اللاحق! ومع ذلك ، فإن كل هذا بعد تنفيذ
BIRMA له الآن أهمية تاريخية بحتة (يمكنك قراءة المزيد حوله
في تقريري في ذلك الوقت ).
النص المخفيلم يتم وضع رموز المصدر في أي مكان بسبب جودتها المنخفضة للغاية - في الحقيقة ، يمكن أن تكون بمثابة نصب تذكاري للتصميم السيئ لأنظمة البرمجيات.
دعونا نلقي نظرة على ميزات استخدام أنماط الخدمة
(٪ all_before) و
(٪ all_after) باستخدام مثال مهمة استخراج بيانات مستخدم معين من موقع ويب محدد. سنقوم بتحليل موقع Amazon ، وتحديداً هذه الصفحة:
https://www.amazon.com/B06-Plus-Bluetooth-Receiver- Streaming /
product-reviews /
B078J3GTRK/ ).
النص المخفييتم أخذ مثال من مهمة اختبار لشغل وظيفة مطور مع تخصص في تحليل البيانات ، أرسلته شركتي ، والتي ، للأسف ، لم تستجب لحل مقترح لي للمشكلة. صحيح ، لقد طلبوا مني فقط وصف العملية العامة للحل - دون تقديم خوارزمية محددة ، ورداً على ذلك حاولت بالفعل الإشارة إلى قوالب Gorp ، بينما كانت الإضافات الخاصة بي موجودة في ذلك الوقت فقط ، كما يقولون ، "على الورق" ".
من أجل الفضول ،
سأسمح لنفسي بالإشارة إلى جزء واحد من خطاب الرد الخاص بي ، والذي ، على ما يبدو ، هو أول ذكر لـ
Gorp.NET ، وإن كان ذا طابع خاص.
"لجعل القائمة الواردة أعلاه من التعبيرات العادية التي استخدمها لحل هذه المشكلة أكثر وضوحًا ، قمت بتجميع قالب جاهز على أساسه (مرفق به الرسالة) ، والذي يمكن استخدامه لاستخراج جميع البيانات الضرورية من خلال تطبيق تطوري الخاص ذي الطابع العالمي ، فقط مصممة لحل هذا النوع من المشاكل. يعتمد الرمز الخاص به على مشروع
github.com/salesforce/gorp ، وفي نفس الصفحة يوجد وصف عام لقواعد تجميع هذه القوالب. بشكل عام ، مثل هذا الوصف في حد ذاته يعني تعيين كل من التعبيرات العادية الملموسة ومنطق معالجتها. النقطة الأكثر صعوبة هنا هي أنه بالنسبة لكل عينة من البيانات ، يجب أن نصف بشكل كامل من خلال النظامي البنية الكاملة للنص الذي يحتوي عليها ، وليس فقط العناصر الفردية نفسها (كما يمكن القيام به عند كتابة برنامجنا الذي يبحث بشكل متسلسل في حلقة ، مثل I سبق وصفه). "
كانت المهمة الأصلية هي جمع البيانات التالية من الصفحة أعلاه:
- اسم المستخدم
- تقييم
- مراجعة العنوان
- التاريخ
- نص
حسنًا ، الآن سأعطيك فقط نموذجًا جمعته بواسطتي ، مما يتيح لك إكمال هذه المهمة بسرعة وكفاءة. أعتقد أن المعنى العام يجب أن يكون واضحًا تمامًا - ربما يمكنك أنت أن تقدم حلاً أكثر إيجازًا.
النص المخفيفي هذا المثال ، بشكل عام ، قمت بتصحيح وظائف ملحقاتي الخاصة لـ Gorp (بالفعل بدون أي هدف للتوظيف ، لكنني أؤسس على أيديولوجية "إثبات الفكرة").
pattern %optspace ( *)
pattern %space ( +)
pattern %cap_letter [AZ]
pattern %small_letter [az]
pattern %letter (%cap_letter|%small_letter)
pattern %endofsentence (\.|\?|\!)+
pattern %delim (\.|\?|\!\,|\:|\;)
pattern %delim2 (\(|\)|\'|\")
pattern %word (%letter|\d)+
pattern %ext_word (%delim2)*%word(%delim)*(%delim2)*
pattern %text_phrase %optspace%ext_word(%space%ext_word)+
pattern %skipped_tags <([^>]+)>
pattern %sentence (%text_phrase|%skipped_tags)+(%endofsentence)?
pattern %start <div class=\"a-fixed-right-grid view-point\">
pattern %username_start <div class=\"a-profile-content\"><span class=\"a-profile-name\">
pattern %username [^\s]+
pattern %username_end </span>
pattern %user_mark_start <i data-hook=\"review-star-rating\"([^>]+)><span class=\"a-icon-alt\">
pattern %user_mark [^\s]+
pattern %user_mark_end ([^<]+)</span>
pattern %title_start data-hook=\"review-title\"([^>]+)>(%skipped_tags)*
pattern %title [^<]+
pattern %title_end </span>
pattern %span class <span class=\"[^\"]*\">
pattern %date_start <span data-hook="review-date"([^>]+)>
pattern %date ([^<]+)
pattern %date_end </span>
pattern %content_start <span data-hook=\"review-body\"([^>]+)>(%skipped_tags)*
pattern %content0 (%sentence)+
pattern %content (%all_after)
pattern %content_end </span>
template @extractUsernameStart (%all_before)%username_start
template @extractUsername $username(%username)%username_end
template @extractUserMarkStart (%all_before)%user_mark_start
template @extractUserMark $user_mark(%user_mark)%user_mark_end
template @extractTitleStart (%all_before)%title_start
template @extractTitle $title(%title)%title_end
template @extractDateStart (%all_before)%date_start
template @extractDate $date(%date)%date_end
template @extractContentStart (%all_before)%content_start
template @extractContent $content(%content)%content_end
extract ToCEntry {
template @extractUsernameStart@extractUsername@extractUserMarkStart@extractUserMark@extractTitleStart@extractTitle@extractDateStart@extractDate@extractContentStart@extractContent
}
هذا ربما كل شيء لهذا اليوم. حول أدوات الجهات الخارجية التي طبقتها ، والتي شارك فيها هذا الإطار بالفعل بشكل كامل ، قد أخبرك مرة أخرى.