كيفية كتابة عنوان المنزل الصحيح؟

كيف دائرة الضرائب ، خريطة الشارع المفتوح ، و InterSystems IRIS
يمكن أن تساعد المطورين في الحصول على عناوين نظيفة


صورة
بيتر بروغيل الأصغر ، دفع الضريبة (جامع الضرائب) ، 1640

في مقالتي السابقة ، قمنا فقط بقشط سطح الأشياء. دعنا نواصل استطلاعنا. موضوع اليوم موضوع صعب. إنها ليست بيانات BIG كبيرة ، لكنها لا تزال البيانات غير سهلة: نحن نتحدث عن كميات كبيرة إلى حد ما من البيانات. لن يصلح كل ذلك لذاكرة الوصول العشوائي في وقت واحد ، وبعضها لن يصلح على محرك الأقراص (ليس بسبب نقص المساحة ، ولكن بسبب وجود الكثير من الخردة). اسم موضوعنا هو FIAS DB : قاعدة بيانات نظام معلومات العنوان الفيدرالي - قواعد بيانات العناوين في روسيا. الأرشيف هو 5.5 جيجابايت. وهو ملف XML مضغوط. بعد الاستخراج ، سيكون 53 جيجا بايت بالكامل (يُخصص 110 غيغابايت للاستخراج). وعندما تبدأ في تحليله وتحويله ، لن يكفي ذلك بسعة 110 جيجابايت. لن يكون هناك ما يكفي من ذاكرة الوصول العشوائي.

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

لكن أول الأشياء أولاً ، نحن نعتبر قاعدة بيانات المشروع المعروف إلى حد ما OpenStreetMaps . تم بناؤه من قبل المتطوعين ، على غرار ويكيبيديا. انها جميلة جدا ومتعددة اللغات. وقد تلقى المشروع لتوه 2018 جائزة مؤسسة البرمجيات الحرة . في الوقت الحالي ، يبلغ حجم الأرشيف بالكامل كملف XML مضغوط 74 غيغابايت.

الحديث عن العناوين ، لقد كنت بعض الأخبار غير المتوقعة من DuckDuckGo ، أفضل محرك بحث آمن حتى الآن أعلن انتقاله إلى خرائط أبل. بتعبير أدق ، إلى Apple MapKit JS. الأكثر إثارة للاهتمام حول هذا لأغراضنا هو "عمليات البحث المحسنة في العناوين". هل Apple أفضل من أي شخص آخر في جمع وحماية بياناتنا بدقة؟ سيتعين علينا مراقبة ...

لذا ، إليك التحدي. كيف يمكننا وضع كل بيانات العنوان في مستودع سهل الاستخدام ، وجعل من الممكن تخيل واجهة برمجة تطبيقات سهلة (في بيثون ، بالطبع) ، ومنع أجهزةنا المحبوبة من الانهيار تحت هذا العبء الهائل؟ دعونا ندعو هذا MicroBigData ، mD أو µBD لفترة قصيرة.

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

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

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

Class Sample.Address Extends %Persistent { Property streetName As %String; Property cityName As %String; Property areaName As %String; Property postalCode As %String; } 

بطبيعة الحال ، سوف يبكي الكثير من الناس ، قائلين أن جميع الحرفيين يخرجون من الجسم. من سمع عن شيء يبث علنا ​​حقوله؟ دعنا نترك الأمر هكذا الآن. إنه مثال بليغ تمامًا ، ويمكن لأي طالب فهمه.

في الواقع ، هذا كل ما نحتاجه. لقد ملأنا الحقول. مخزنة لهم. سلمهم إلى أشياء أخرى. شخص آخر سيرثهم. كل شيء يعمل. ويتم تخزينه!

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

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

دعونا نلقي نظرة على مثال واقع الحياة. يتم تشغيل Google الآن بواسطة Sundar Pichai. هو من الهند. ولد في مدينة تشيناي. أم أنها مدراس؟ في عام 1996 ، قرر السكان أن اسم المدينة بدا برتغاليًا جدًا وأطلق عليه اسم عاصمة ولاية تاميل نادو من مدراس إلى تشيناي. إذن ما الذي يجب أن يدخله سوندر و 72 مليون مواطن في وثائقهم الإلكترونية؟

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

باختصار ، السياق هو أهم شيء. ويتيح لنا نموذج الكائن استخدامه المباشر من خلال تغليف "بيانات الجهاز" وتنفيذ سلوك "الحياة الواقعية" المعتمد على السياق. ليس الأمر أن tuples منخفض المستوى مرتبة في الجداول ؛-)

في غضون ذلك ، سنعود إلى التنفيذ "البدائي" ونجعل الأمور أكثر صعوبة لأنفسنا. للبدء ، سنقضي على الأخطاء والتكرارات. بمعنى آخر ، سوف نبحث عن طريقة لكتابة العناوين بشكل صحيح في المرة الأولى. في الوقت نفسه ، سنساعد مطوري واجهة المستخدم على تقديم تلميحات للمستخدمين عند قيامهم بإدخال البيانات في الحقول.
عندما يكون هناك شيئان في مكان واحد - النصوص ومنصة بيانات InterSystems IRIS - يتمتع المطور بفرصة حقيقية لتغيير الأمور دون الابتعاد عن الجهاز. باستخدام مكونات الكائنات المدمجة iKnow و iFind ، على سبيل المثال. وتهدف هذه المكونات للعمل مع البيانات غير المهيكلة والبحث عن النص الكامل ، على التوالي.
دعنا نحاول العثور على مخطط البيانات لـ OpenStreetMap. الأمر ليس سهلاً كما قد يبدو في البداية. لا أعرف السبب الدقيق ، لكن لا يوجد نظام بيانات لنظام التشغيل OSM . وسوف يساعدنا كثيرا ، كما سنرى أدناه! وهذا لن يعيد اختراع العجلة ، استخدم XSD مناسبًا ، وجدته لك. وشكرا ، أوليفر شرينك. هنا المزيد من الصور . يجب أن أقول أنه لأغراضنا فهو مناسب ويتوافق مع البنية الداخلية لملفات XML وتنزيلات OSM. لماذا هو مهم ، ولكن السطر الأول في ملف XSD يجب أن يبدأ بـ "<؟ Xml ...".

العناصر هي المكونات الأساسية لنموذج البيانات النظرية لـ OpenStreetMap للعالم المادي. انها تتكون من

  • العقد - تحديد النقاط في الفضاء ،
  • طرق - تحديد الميزات الخطية وحدود المنطقة ، و
  • العلاقات - التي تستخدم في بعض الأحيان لشرح كيف تعمل العناصر الأخرى معا.

يمكن أن يكون لكل ما سبق علامة أو أكثر مرتبطة (تصف معنى عنصر معين). تتكون العلامة من عنصرين ، مفتاح ، وقيمة. تصف العلامات ميزات محددة لعناصر الخريطة: العقد أو الطرق أو العلاقات.

أين الشوارع والمدن؟ إنه سر كبير! الهندسة كانت تدرس جيدا؟ المزيد عن هذا في المرة القادمة. :)

بالإضافة إلى ذلك ، سوف نستخدم معالج مخطط XSD ، المصنوع من قبل مطوري IRIS ، من أجل فئة XML المناسبة. علامة النسبة المئوية في البداية تعني فقط أن هذه فئة من مكتبة النظام. يمكن الاطلاع على مزيد من المعلومات حول ذلك في الوثائق . سوف نقوم بالعمليات في المحطة.

 set xmlSchema = ##class(%XML.Utils.SchemaReader).%New() do xmlSchema.Process("/path/to/OSMSchema.xsd") 

يمكنك الحصول على نفس الشيء من Atelier IDE (في القائمة ، انتقل إلى أدوات> الوظائف الإضافية> معالج مخطط XML):

صورة

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

 python3 -m http.server 80 

يمكنك استخدام أي خادم HTTP آخر تريده. أو قم بتحميل الملف على خادم IRIS وأشر إليه.

نتيجة لذلك ، لدينا ثمانية فصول تعكس تمامًا هيكل عنواننا XML. هذه هي الفئة الرئيسية OSM.osm:

 Class OSM.osm Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "osm"; Parameter XMLSEQUENCE = 1; Property bounds As OSM.bounds(XMLNAME = "bounds", XMLREF = 1) [ Required ]; Relationship node As OSM.node(XMLNAME = "node", XMLPROJECTION = "ELEMENT", XMLREF = 1) [ Cardinality = many, Inverse = osm ]; Relationship way As OSM.way(XMLNAME = "way", XMLPROJECTION = "ELEMENT", XMLREF = 1) [ Cardinality = many, Inverse = osm1 ]; Relationship relation As OSM.relation(XMLNAME = "relation", XMLPROJECTION = "ELEMENT", XMLREF = 1) [ Cardinality = many, Inverse = osm2 ]; Property version As %xsd.float(XMLNAME = "version", XMLPROJECTION = "ATTRIBUTE") [ InitialExpression = ".6", ReadOnly ]; Property generator As %String(MAXLEN = "", XMLNAME = "generator", XMLPROJECTION = "ATTRIBUTE") [ InitialExpression = "CGImap 0.0.2", ReadOnly ]; } 

و OSM.node:

 Class OSM.node Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "node"; Parameter XMLSEQUENCE = 1; Relationship tag As OSM.tag(XMLNAME = "tag", XMLPROJECTION = "ELEMENT", XMLREF = 1) [ Cardinality = many, Inverse = node ]; Property id As %xsd.unsignedLong(XMLNAME = "id", XMLPROJECTION = "ATTRIBUTE"); Property lat As %xsd.double(XMLNAME = "lat", XMLPROJECTION = "ATTRIBUTE"); Property lon As %xsd.double(XMLNAME = "lon", XMLPROJECTION = "ATTRIBUTE"); Property user As %String(MAXLEN = "", XMLNAME = "user", XMLPROJECTION = "ATTRIBUTE") [ SqlFieldName = _user ]; Property uid As %xsd.unsignedLong(XMLNAME = "uid", XMLPROJECTION = "ATTRIBUTE"); Property visible As %Boolean(XMLNAME = "visible", XMLPROJECTION = "ATTRIBUTE"); Property version As %xsd.unsignedLong(XMLNAME = "version", XMLPROJECTION = "ATTRIBUTE"); Property changeset As %xsd.unsignedLong(XMLNAME = "changeset", XMLPROJECTION = "ATTRIBUTE"); Property timestamp As %TimeStamp(XMLNAME = "timestamp", XMLPROJECTION = "ATTRIBUTE"); Relationship osm As OSM.osm(XMLPROJECTION = "NONE") [ Cardinality = one, Inverse = node ]; } 

كما ترون ، فإن بعض الخيارات التي قمت بتعطيلها بالفعل غير ضرورية لحلنا.

حجم ملف XML فقط لروسيا هو حوالي 53 جيجابايت. لا يمكنك فتحه باستخدام أدوات معالجة النصوص المعتادة: فهي لا تستطيع إضافة ملفات بهذا الحجم الكبير. يمكنك أخذ عينات أصغر للتمرين ، على سبيل المثال ، تتوفر عناوين روسيا للمناطق الفردية . الحجم الصغير لمنطقة كالينينجراد بتنسيق مضغوط سيكون 18 ميجابايت ، وملف XML غير مضغوط هو 203 ميجابايت.
بالمناسبة ، يبلغ الحد الأقصى لطول السلسلة الحرفية في InterSystems IRIS 3،641،144 حرفًا. بمعنى آخر ، لن ينجح تحميل ملف أو عنوان URL مباشرة فيه. يمكنك رؤية الحدود الأخرى في الوثائق . للعمل مع كميات كبيرة من البيانات ، يمكنك استخدام تدفقات البيانات التي لا تحتوي على قيود طول.
دعونا نرى ما نحصل عليه لمجموعة العقدة.

بعد ذلك ، سنفعل الأشياء حسب الكتاب . سنقوم بإنشاء كائن يفهم XML كلغة أصلية باستخدام فئة من مكتبة النظام٪ XML.Reader:

 set reader = ##class(%XML.Reader).%New() 

سنعطيها تعليمات حول ما يجب أخذه وتجاهل الباقي. سنتخذ فصل واحد:

 do reader.Correlate("node","OSM.node") 

بعد ذلك ، هناك طرق مختلفة للحصول على ملف mBD الأصلي. إذا كان ذلك مناسبًا ، فيمكنك وضعه بجوار مستودع التخزين محليًا في نظام الملفات لخادم IRIS. أو ، كما في المثال الخاص بي ، اطلب إرسالها عبر HTTP. يوجد أيضًا خيار أكثر عالمية ، سأتحدث عنه قليلاً أدناه.

 set url="http://localhost/kaliningrad-latest.osm" write reader.OpenUrl(url) 

! المهم في هذه المرحلة ، سيواجه معظم الأشخاص الذين يجربون هذا المثال لأنفسهم شيئًا مروعًا. بدلاً من "1" سعيد (كل شيء على ما يرام) ، سيعود النظام شيئًا يبدأ بـ "0 ، مخزن ..." وسيكون ذلك مخيباً للآمال. بمعنى آخر ، تبين أن الملف الذي يبدو أنه mBD ليس دقيقًا جدًا ، ولن يتناسب مع هدفنا. لم يكن هناك ما يكفي من الذاكرة المخصصة لذلك. يمكن أن تكون ثابتة؟ تماما. تتيح لك منصة بيانات IRIS إنشاء كائنات تصل إلى 4 تيرابايت في ذاكرة الوصول العشوائي. إذن ما الخطأ الذي حدث؟ تبعًا للإعدادات الافتراضية ، يكون حجم الكائن هو 256 ميجابايت في إعدادات النظام. لكننا نحتاج أكثر من ذلك بكثير. وتذكر ، هذه هي متطلبات ذاكرة الوصول العشوائي. هل لديك مساحة كافية على جهاز الكمبيوتر / الخادم الخاص بك؟
لقد جربت تحديد مقدار الذاكرة التي سنحتاجها لاستيعاب هذا العملاق: حوالي 170 جيجابايت. يجب تحديد هذا في الإعدادات (القائمة> تكوين الذاكرة> سعة الذاكرة القصوى لكل عملية (KB)) أو من خلال متغير النظام $ ZSTORAGE (بالكيلوبايت):

 set $ZSTORAGE=170000000 

هل قمت بتشغيل عملية جديدة باستخدام إعدادات الذاكرة الصحيحة؟ ثم الجزء التالي سهل: لقد قرأنا وحفظنا.

يوجد أيضًا خيار بديل (وربما أفضل): استخدام خاصية UsePPG Handler لفئة ٪ XML. Reader ، والتي تتيح لك عدم تخزين XML في الذاكرة ويعمل مع إعدادات الذاكرة القياسية.

 set reader = ##class(%XML.Reader).%New() set reader.UsePPGHandler = 1 

التالي ... الارتباط / القراءة ، إلخ. ...

 do reader.Next(.object) do object.%Save() 

وهكذا ، 1180849 مرة لكل عملية :-) إنها مملة. لهذا السبب سنضيف طريقة فئة OSM.map للاستيراد ، بناءً على نفس الأوامر:

 ClassMethod Import(url) { Set reader = ##class(%XML.Reader).%New() Set reader.UsePPGHandler = 1 Set status = reader.OpenURL(url) Do reader.Correlate("node","OSM.node") While (reader.Next(.object)) { Do object.%Save() } //back to top of XML file Do reader.Rewind() Do reader.Correlate("way","OSM.way") While (reader.Next(.object)) { Do object.%Save() } Do reader.Rewind() Do reader.Correlate("relation","OSM.relation") While (reader.Next(.object)) { Do object.%Save() } } 

سنستخدم قوة exocortex على جهاز الكمبيوتر الخاص بنا من خلال أمر واحد فقط في الجهاز :

 do ##class(OSM.osm).Import("http://localhost/kaliningrad-latest.osm") 

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

والآن دعنا نصل إلى ما هو غير مفهوم - سنقوم بتعليم العنوان لقراءة البيانات الصحيحة من مصدرنا. لحسن الحظ ، تحتوي مجموعة بيانات خدمة الضرائب الفيدرالية على أوصاف جاهزة لهيكل مستند XML. وفقًا للوصف الوارد من موقع FIAS على الويب المصاحب للبيانات ، سنحتاج إلى مجموعة بيانات ADDROBJ التي ، في حالتي ، تتوافق مع الملف AS_ADDROBJ_2_250_01_04_01_01.xsd

بعد ذلك ، دعونا نستخدم معالج مخطط XSD. سوف نقوم بالعمليات في المحطة:

 set xmlScheme = ##class(%XML.Utils.SchemaReader).%New() do xmlScheme.Process("/path/to/AS_ADDROBJ_2_250_01_04_01_01.xsd") 

نتيجة لذلك ، لدينا فئتان تعكسان تمامًا هيكل عنواننا XML:

Test.AddressObjects

 /// Composition and structure of the file with classifier information for FIAS DB elements in address form Class Test.AddressObjects Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "AddressObjects"; Parameter XMLSEQUENCE = 1; /// Classifier for elements in address form Relationship Object As Test.Object(XMLNAME = "Object", XMLPROJECTION = "ELEMENT") [ Cardinality = many, Inverse = AddressObjects ]; } 

Test.Object

 /// Created from: http://localhost:28869/AS_ADDROBJ_2_250_01_04_01_01.xsd Class Test.Object Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "Object"; Parameter XMLSEQUENCE = 1; /// Global unique identifier of the address object Property AOGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOGUID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Formal name Property FORMALNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "FORMALNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Region code Property REGIONCODE As %String(MAXLEN = 2, MINLEN = 2, XMLNAME = "REGIONCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Autonomy code Property AUTOCODE As %String(MAXLEN = 1, MINLEN = 1, XMLNAME = "AUTOCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Area code Property AREACODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "AREACODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// City code Property CITYCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "CITYCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Code of area within city Property CTARCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "CTARCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Locality code Property PLACECODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "PLACECODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Planning structure element code Property PLANCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "PLANCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Street code Property STREETCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "STREETCODE", XMLPROJECTION = "ATTRIBUTE"); /// Code of additional element in address form Property EXTRCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "EXTRCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Code of subordinate additional element in address form Property SEXTCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "SEXTCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Official name Property OFFNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "OFFNAME", XMLPROJECTION = "ATTRIBUTE"); /// Postal code Property POSTALCODE As %String(MAXLEN = 6, MINLEN = 6, XMLNAME = "POSTALCODE", XMLPROJECTION = "ATTRIBUTE"); /// Federal Tax Service - Private Individual code Property IFNSFL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "IFNSFL", XMLPROJECTION = "ATTRIBUTE"); /// Federal Tax Service - Private Individual territorial district code Property TERRIFNSFL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "TERRIFNSFL", XMLPROJECTION = "ATTRIBUTE"); /// Federal Tax Service - Legal Entity code Property IFNSUL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "IFNSUL", XMLPROJECTION = "ATTRIBUTE"); /// Federal Tax Service - Legal Entity territorial district code Property TERRIFNSUL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "TERRIFNSUL", XMLPROJECTION = "ATTRIBUTE"); /// Russian Classification on Objects of Administrative Division Property OKATO As %String(MAXLEN = 11, MINLEN = 11, XMLNAME = "OKATO", XMLPROJECTION = "ATTRIBUTE"); /// Russian Classification of Territories of Municipal Formations Property OKTMO As %String(MAXLEN = 11, MINLEN = 8, XMLNAME = "OKTMO", XMLPROJECTION = "ATTRIBUTE"); /// Date of record entry Property UPDATEDATE As %Date(XMLNAME = "UPDATEDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Short name of object type Property SHORTNAME As %String(MAXLEN = 10, MINLEN = 1, XMLNAME = "SHORTNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Address object level Property AOLEVEL As %Integer(XMLNAME = "AOLEVEL", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Object identifier of the parent object Property PARENTGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PARENTGUID", XMLPROJECTION = "ATTRIBUTE"); /// Unique record identifier. Key field. Property AOID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Record identifier associated with previous historical record Property PREVID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PREVID", XMLPROJECTION = "ATTRIBUTE"); /// Record identifier associated with next historical record Property NEXTID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "NEXTID", XMLPROJECTION = "ATTRIBUTE"); /// Address object code in one string with validity indicator from Russian Classifier of Addresses (KLADR) 4.0. Property CODE As %String(MAXLEN = 17, MINLEN = 0, XMLNAME = "CODE", XMLPROJECTION = "ATTRIBUTE"); /// Address object code from KLADR 4.0 in one string without validity indicator (last two digits) Property PLAINCODE As %String(MAXLEN = 15, MINLEN = 0, XMLNAME = "PLAINCODE", XMLPROJECTION = "ATTRIBUTE"); /// Validity status of FIAS address object. Current address as of today's date. Usually the last entry about the address object. /// 0 - Not current /// 1 - Current Property ACTSTATUS As %Integer(XMLNAME = "ACTSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Center status Property CENTSTATUS As %Integer(XMLNAME = "CENTSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Operation status on record - reason for record's appearance (see description of OperationStatus table): /// 01 – Activation; /// 10 – Addition; /// 20 – Change; /// 21 – Group change; /// 30 – Deletion; /// 31 - Deletion due to the deletion of the parent object; /// 40 – Attachment of the address object (merger); /// 41 – Reassignment due to the merger of the parent object; /// 42 - Termination due to the attachment to another address object; /// 43 - Creation of a new address object due to a merger of address objects; /// 50 – Reassignment; /// 51 – Reassignment due to the reassignment of the parent object; /// 60 – Termination due to segmentation; /// 61 – Creation of a new address object due to segmentation Property OPERSTATUS As %Integer(XMLNAME = "OPERSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// KLADR 4 validity status (last two digits in the code) Property CURRSTATUS As %Integer(XMLNAME = "CURRSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Start of record operation Property STARTDATE As %Date(XMLNAME = "STARTDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// End of record operation Property ENDDATE As %Date(XMLNAME = "ENDDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Foreign key to requirements document Property NORMDOC As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "NORMDOC", XMLPROJECTION = "ATTRIBUTE"); /// Current address object indicator Property LIVESTATUS As %xsd.byte(VALUELIST = ",0,1", XMLNAME = "LIVESTATUS", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Address type: /// 0 - not defined /// 1 - municipal; /// 2 - administrative/territorial Property DIVTYPE As %xsd.int(VALUELIST = ",0,1,2", XMLNAME = "DIVTYPE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; Relationship AddressObjects As Test.AddressObjects(XMLPROJECTION = "NONE") [ Cardinality = one, Inverse = Object ]; } 

من القائمة الكاملة لملفات XML في FIAS ، سنستخدم الملف مع أسماء المناطق والمدن والشوارع فقط. عندما كنت أستعد للنشر ، كان لي هذا:

 AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML 


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

 Class FIAS.AddressObject Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "Object"; Parameter XMLSEQUENCE = 1; /// Global unique identifier of the address object Property AOGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOGUID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Official name Property OFFNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "OFFNAME", XMLPROJECTION = "ATTRIBUTE"); /// Postal code Property POSTALCODE As %String(MAXLEN = 6, MINLEN = 6, XMLNAME = "POSTALCODE", XMLPROJECTION = "ATTRIBUTE"); /// Short name of object type Property SHORTNAME As %String(MAXLEN = 10, MINLEN = 1, XMLNAME = "SHORTNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Address object level Property AOLEVEL As %Integer(XMLNAME = "AOLEVEL", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Object identifier of the parent object Property PARENTGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PARENTGUID", XMLPROJECTION = "ATTRIBUTE"); /// Unique record identifier. Key field. Property AOID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; } 

سنقوم بإنشاء كائن يفهم XML كلغة أصلية باستخدام فئة من مكتبة النظام٪ XML.Reader:

 set reader = ##class(%XML.Reader).%New() 

سنعطيها تعليمات حول من يجب أن يأخذها ، ونقول لها أن تتجاهل الباقي. سنتخذ حصة واحدة للاختبار.

التالي ... الارتباط / القراءة ، إلخ. ...

 do reader.Correlate("Object","FIAS.AddressObject") set url="http://localhost/AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML" write reader.OpenUrl(url) 

ثم الجزء التالي سهل: لقد قرأنا وحفظنا.

 do reader.Next(.object) do object.%Save() 

وهكذا ، 3،722،548 مرة لكل عملية :-)

إنه أكثر إرهاقًا من ذي قبل. لهذا السبب سنضيف طريقة فئة FIAS.AddressObject للاستيراد ، بناءً على نفس الأوامر:

 ClassMethod Import() { // Create object to read XML Set reader = ##class(%XML.Reader).%New() // Get source XML for parsing Set status = reader.OpenURL("http://localhost/AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML") If $$$ISERR(status) {Do $System.Status.DisplayError(status)} // Join object with the right sample structure Do reader.Correlate("Object","FIAS.AddressObject") // Read and save the object in storage While (reader.Next(.object,.status)) { Set status = object.%Save() If $$$ISERR(status) {do $System.Status.DisplayError(status)} } // If an error occurs during parsing, display a message If $$$ISERR(status) {Do $System.Status.DisplayError(status) } 

سنستخدم قوة exocortex على جهاز الكمبيوتر الخاص بنا من خلال أمر واحد فقط في الجهاز :

 do ##class(FIAS.AddressObject).Import() 

صورة

العشاء جاهز ، الجميع. لقد كان mBD ، والآن هو الطبق النهائي ، عالمي بأسماء التحقق من المدن الروسية.

صورة

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

لم يكن هناك مساحة كافية هنا لمزيد من المعلومات حول كائنات ObjectScript الجميلة و Python API. ستكون هذه قصة أخرى.
أخبار سارة: أكملت Gartner لتوها مجموعتها السنوية من تقييمات المستخدمين الفعليين وتعليقاتهم في فئة قواعد بيانات إدارة قواعد البيانات واستخدمت هذه المعلومات لنشر تصنيفاتها لأفضل نظم إدارة قواعد البيانات لعام 2019. حصلت InterSystems Caché و InterSystems IRIS Data Platform على أعلى تصنيف لـ "العملاء" "الاختيار". يمكنك التحقق من المنتجات التي تم النظر فيها وكيف تم تصنيفها.
أفضل برامج أنظمة إدارة قواعد البيانات التشغيلية لعام 2019 كما استعرضها العملاء.

صورة

Source: https://habr.com/ru/post/ar446376/


All Articles