Bagaimana cara menuliskan alamat rumah?

Bagaimana Layanan Pajak, OpenStreetMap, dan InterSystems IRIS
dapat membantu pengembang mendapatkan alamat yang bersih


gambar
Pieter Brueghel yang Muda, Membayar Pajak (Pemungut Pajak), 1640

Dalam artikel saya sebelumnya , kami hanya melihat permukaan benda. Mari kita lanjutkan pengintaian kita. Topik hari ini adalah topik yang sulit. Ini bukan DATA BESAR, tetapi masih merupakan data yang tidak mudah untuk dikerjakan: kita sedang berbicara tentang jumlah data yang cukup besar. Semuanya tidak akan masuk ke RAM sekaligus, dan beberapa bahkan tidak muat di drive (bukan karena kurangnya ruang, tetapi karena ada banyak sampah). Nama subjek kami adalah FIAS DB : database Sistem Informasi Alamat Federal - basis data alamat di Rusia. Arsipnya 5,5 GB. Dan itu adalah file XML terkompresi. Setelah ekstraksi, ini akan menjadi penuh 53 GB (sisihkan 110 GB untuk ekstraksi). Dan ketika Anda mulai mem-parsing dan mengubahnya, 110 GB itu tidak akan cukup. RAM juga tidak akan cukup.

Itu semua akan baik-baik saja, tetapi Anda bisa terus menggali. Sudah ada proyek sumber terbuka internasional untuk mengumpulkan dan mensistematisasikan data alamat: OpenAddresses . Basis data mereka akan lebih besar. Saat ini ada banyak tempat kosong di peta mereka. Rusia, misalnya, hampir kosong. Ukuran arsip ini adalah 10 GB.

Tetapi hal pertama yang pertama, kami mempertimbangkan database dari proyek OpenStreetMaps yang cukup terkenal. Itu dibangun oleh sukarelawan, mengikuti contoh Wikipedia. Ini cukup menyeluruh dan multibahasa. Dan proyek ini baru saja menerima penghargaan The Free Software Foundation 2018 . Saat ini, ukuran seluruh arsip sebagai file XML terkompresi adalah 74 GB.

Berbicara tentang alamat, saya telah mendengar beberapa berita tak terduga dari DuckDuckGo , mesin pencari terbaik dan aman saat ini mengumumkan kepindahannya ke Apple Maps. Lebih tepatnya, ke Apple MapKit JS. Yang paling menarik tentang ini untuk tujuan kami adalah "pencarian alamat yang ditingkatkan." Apakah Apple lebih baik daripada orang lain dalam mengumpulkan dan melindungi data kita dengan cermat? Kita harus mengawasi ...

Jadi, inilah tantangannya. Bagaimana kita bisa meletakkan semua data alamat ini ke dalam repositori yang mudah digunakan, memungkinkan untuk membayangkan API yang mudah (tentu saja dengan Python), dan mencegah perangkat keras kita yang dicintai runtuh di bawah beban besar ini? Sebut saja MicroBigData, mD, atau ΞΌBD ini.

Hampir setiap pengembang telah mendengar sindiran berikut. Direktori alamat adalah direktori nama tempat, yang merupakan hal yang sangat berguna. Saya tidak tahu persis berapa banyak data alamat di proyek Anda yang terbaru. Bagaimanapun, ada begitu banyak daerah, kota, dan jalan. Tetapi tampaknya mereka diperlukan untuk proyek apa pun yang melibatkan orang. Ada alamat di mana Anda dapat menemukan seseorang atau mengirim mereka paket. Lalu ada informasi yang diperlukan untuk paspor dan dokumen lainnya. Dan mungkin ada alamat kantor atau tengara yang direkomendasikan seseorang kepada Anda. Jadi apa yang harus kamu lakukan? Di mana Anda harus mendapatkannya?

Tanpa memperhitungkan kesalahan dan duplikat, solusi paling sederhana melibatkan objek primitif yang berisi string string literal (atau konstanta string). Biarkan pengguna membuat entri tambahan. Dan benda tahu bagaimana menyelamatkan diri, seperti yang telah kita bahas sebelumnya .

Ambil objek yang dijelaskan dalam kelas di bawah ini sebagai contoh. Kasing buku teks , meskipun dalam bentuk alamat USA, tetapi dengan penyesuaian untuk dataset Rusia kami: kode pos alih-alih ZIP. Saya juga akan mengubah kode pos menjadi angka, tetapi saya akan membiarkannya sebagai string agar semuanya tetap seragam. Siapa pun yang mengenali bahasa (ObjectScript) segera akan mendapatkan "suka" yang gratis.

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

Tentu saja, banyak orang akan menangis busuk, mengatakan semua literal mencuat dari objek. Siapa yang pernah mendengar benda yang mengudara di depan umum? Mari kita biarkan seperti itu untuk saat ini. Ini adalah contoh yang cukup fasih, dan setiap siswa dapat memahaminya.

Sebenarnya, hanya itu yang kita butuhkan. Kami mengisi kolom. Menyimpannya. Menyerahkannya ke benda lain. Orang lain akan mewarisinya. Semuanya bekerja. Dan itu tersimpan!

Tetapi saya harus mengatakan beberapa kata tentang mengapa itu tidak boleh dilakukan dengan cara ini. Apa Alamat objek kami? Mengapa tidak bisa hanya sekelompok string teks? Keberatan paling jelas yang muncul dari konteks: siapa yang menggunakan Alamat ini, dalam bentuk apa mereka menggunakannya, dan untuk tujuan apa? Cobalah untuk menempatkan logika programmer Anda ke samping dan bayangkan bagaimana "turis asing," "sejarawan," "pemungut pajak," atau "pengacara" berpikir.

Saya menduga Anda segera memunculkan banyak pertanyaan tambahan: bahasa dan pengodean apa yang harus digunakan, periode waktu apa yang harus dipertimbangkan, dan jenis dokumen apa yang terlibat dalam operasi ini: legal atau pos? Dan sebuah kota: apakah itu nama lokalitas, atau apa? Bahkan jalan bisa menjadi bulevar, lajur, jalan, atau yang lainnya. Bagaimana seharusnya semua detail penting ini ditangani?

Mari kita lihat contoh kehidupan nyata. Google sekarang dijalankan oleh Sundar Pichai. Dia dari India. Ia dilahirkan di kota Chennai. Atau Madras? Pada tahun 1996, penduduk memutuskan bahwa nama kota itu terdengar terlalu Portugis dan berganti nama menjadi ibu kota negara bagian Tamil Nadu dari Madras ke Chennai. Jadi apa yang harus dimasukkan Sundar dan 72 juta rekan senegaranya ke dalam dokumen elektronik mereka?

Bahkan, ada seluruh ilmu yang mempelajari ini: toponim terapan .
Jadi, ada beberapa pertanyaan lanjutan. Bagaimana seharusnya waktu dan tanggal ditangani? Bagaimana dengan yang jelas, uang ? Atau koordinat geografis? Dan bagaimana Anda menerapkan ini dalam kode Anda? Dan apakah Anda dapat mentransfernya ke DBMS pilihan Anda tanpa menurunkan lapisan abstraksi? Bagaimana Anda menghindari spiral ke bawah ke tipe atom data mesin dan pemikiran konstan tentang rekonstruksinya? Dalam hal ini, ada baiknya mencari sumber dari API primitif atau berkualitas baik. Pikirkan ini di waktu luang Anda.

Singkatnya, konteks adalah hal yang paling penting. Dan model objek memungkinkan kita untuk menggunakannya secara langsung dengan merangkum "data mesin" dan menerapkan perilaku "kehidupan nyata" yang bergantung pada konteks. Bukan karena tuple tingkat rendah diatur dalam tabel ;-)

Sementara itu, kami akan kembali ke implementasi "primitif" dan membuat segalanya lebih sulit bagi diri kita sendiri. Untuk memulai, kami akan menghilangkan kesalahan dan duplikat. Dengan kata lain, kami akan mencari cara untuk menulis alamat dengan benar saat pertama kali. Pada saat yang sama, kami akan membantu pengembang UI memberikan petunjuk bagi pengguna saat mereka memasukkan data ke dalam bidang.
Ketika ada dua hal di satu tempat - teks dan platform data IRIS InterSystems - seorang pengembang memiliki peluang nyata untuk benar-benar membalikkan keadaan tanpa meninggalkan mesin. Dengan menggunakan komponen objek yang tertanam, iKnow dan iFind , misalnya. Komponen-komponen ini dimaksudkan untuk bekerja dengan data yang tidak terstruktur dan pencarian teks lengkap .
Mari kita coba cari skema data untuk OpenStreetMap. Ini tidak semudah kelihatannya pada awalnya. Saya tidak tahu alasan pastinya, tetapi tidak ada skema data untuk OSM . Dan itu akan banyak membantu kita, seperti yang akan dilihat di bawah ini! Dan itu tidak akan menciptakan kembali roda, gunakan XSD yang cocok , yang saya temukan untuk Anda. Dan terima kasih, Oliver Schrenk. Ini lebih banyak gambar . Saya harus mengatakan bahwa untuk keperluan kami, ini sesuai dan sesuai dengan struktur internal file XML dan unduhan OSM. Mengapa ini penting, tetapi baris pertama dalam file XSD harus dimulai dengan "<? Xml ...".

Elemen adalah komponen dasar dari model data konseptual OpenStreetMap tentang dunia fisik. Mereka terdiri dari

  • node - mendefinisikan titik-titik dalam ruang,
  • cara - mendefinisikan fitur linier dan batas wilayah, dan
  • hubungan - yang kadang-kadang digunakan untuk menjelaskan bagaimana elemen-elemen lain bekerja bersama.

Semua hal di atas dapat memiliki satu atau lebih tag terkait (yang menggambarkan arti elemen tertentu). Tag terdiri dari dua item, kunci, dan nilai. Tag menggambarkan fitur spesifik elemen peta: node, cara, atau hubungan.

Di mana jalan-jalan dan kota-kota? Itu rahasia besar! Geometri itu diajarkan dengan baik? Lebih lanjut tentang ini lain kali. :)

Selain itu, kami akan menggunakan wizard skema XSD, yang dibuat dengan anggun untuk kami oleh pengembang IRIS, untuk kelas% XML yang sesuai. Tanda persen di awal hanya berarti bahwa ini adalah kelas dari pustaka sistem. Informasi lebih lanjut tentang itu dapat ditemukan di dokumentasi . Kami akan melakukan operasi di terminal.

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

Anda bisa mendapatkan hal yang sama dari Atelier IDE (di menu, buka Tools> Add-Ins> Wizard Skema XML):

gambar

Karena kami menggunakan wizard dengan menunjukkan nama paket yang dihasilkan dan bukan parameter, mereka berakhir di paket Tes. Seperti yang dapat Anda lihat dari perintah kedua, saya meneruskan file skema ke server Python lokal saya:

 python3 -m http.server 80 

Anda dapat menggunakan http-server lain yang Anda inginkan. Atau muat file di server IRIS Anda dan arahkan ke sana.

Akibatnya, kami memiliki delapan kelas yang sepenuhnya mencerminkan struktur XML alamat kami. Ini adalah kelas utama 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 ]; } 

Dan 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 ]; } 

Seperti yang Anda lihat, beberapa opsi yang telah saya nonaktifkan sebagai solusi yang tidak perlu.

Ukuran file XML hanya untuk Rusia adalah sekitar 53 GB. Anda tidak dapat membukanya dengan alat pemrosesan teks yang biasa: mereka tidak dapat menerima file sebesar ini. Anda dapat mengambil sampel yang lebih kecil untuk berolahraga, misalnya, alamat Rusia tersedia untuk masing-masing wilayah . Volume kecil wilayah Kaliningrad dalam format terkompresi akan menjadi 18 MB, file XML yang tidak terkompresi adalah 203 MB.
Omong-omong, panjang maksimum string literal dalam InterSystems IRIS adalah 3.641.144 karakter. Dengan kata lain, memuat file atau URL secara langsung ke dalamnya tidak akan berfungsi. Anda dapat melihat batasan lain dalam dokumentasi . Untuk bekerja dengan sejumlah besar data, Anda dapat menggunakan aliran data yang tidak memiliki batasan panjang.
Mari kita lihat apa yang kita dapatkan untuk set node.

Selanjutnya, kita akan melakukan hal-hal berdasarkan buku . Kami akan membuat objek yang memahami XML sebagai bahasa asli dengan menggunakan kelas dari pustaka sistem% XML.Reader:

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

Kami akan memberikan instruksi tentang apa yang harus diambil, dan mengabaikan sisanya. Kami akan mengambil satu kelas:

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

Setelah itu, ada berbagai cara untuk mendapatkan file mBD asli. Jika nyaman, Anda bisa meletakkannya di sebelah repositori penyimpanan, secara lokal di sistem file server IRIS. Atau, seperti dalam contoh saya, minta dikirim melalui HTTP. Ada juga opsi yang lebih universal, yang akan saya bicarakan sedikit di bawah.

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

Penting! Pada titik ini, kebanyakan orang yang mencoba contoh ini sendiri akan menghadapi sesuatu yang mengerikan. Alih-alih senang "1" (semuanya baik-baik saja), sistem akan mengembalikan sesuatu yang dimulai dengan "0, STORE ..." Dan itu akan mengecewakan. Dengan kata lain, file dengan apa yang tampaknya mBD ternyata tidak terlalu mikro, dan tidak akan sesuai dengan objek kita. Tidak ada cukup memori yang dialokasikan untuk itu. Bisakah ini diperbaiki? Tentu saja Platform data IRIS memungkinkan Anda membuat objek hingga 4 TB dalam RAM. Jadi apa yang salah? Secara default, ukuran objek adalah 256 MB dalam pengaturan sistem. Tetapi kita membutuhkan lebih dari itu. Dan ingat, ini adalah persyaratan RAM. Apakah Anda memiliki cukup ruang di komputer / server Anda?
Saya bereksperimen untuk menentukan jumlah memori yang kami perlukan untuk mengakomodasi raksasa ini: hampir 170 GB. Ini harus ditentukan dalam pengaturan (Menu> Konfigurasi memori> Kapasitas memori maks per proses (KB)) atau melalui variabel sistem $ ZSTORAGE (dalam kilobyte):

 set $ZSTORAGE=170000000 

Apakah Anda menjalankan proses baru dengan pengaturan memori yang tepat? Maka bagian selanjutnya mudah: kita hanya membaca dan menyimpan.

Ada juga opsi alternatif (dan mungkin lebih disukai): gunakan properti UsePPG Handler dari kelas% XML. Reader, yang memungkinkan Anda untuk tidak menyimpan XML dalam memori dan bekerja dengan pengaturan memori standar.

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

Selanjutnya ... Korelasi / Baca, dll. ...

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

Dan seterusnya, 1.180.849 kali untuk setiap operasi :-) Ini membosankan. Itu sebabnya kami akan menambahkan metode kelas OSM.map kami untuk mengimpor, berdasarkan pada perintah yang sama:

 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() } } 

Kami akan menggunakan kekuatan eksokorteks komputer kami hanya dengan satu perintah di terminal :

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

Jadi, kami mendapatkan data alamat dari tempat terbuka dan mungkin bukan sumber yang sangat andal. Sudah waktunya untuk melewati tahap yang sama, tetapi pada data yang dapat dipercaya. Dan juga terstandarisasi, dibersihkan, didokumentasikan dengan baik, dan dibuat oleh badan pemerintah yang tepat: itu adalah legenda. Untuk kreditnya, layanan pajak Rusia melakukan pekerjaan yang baik dengan produk digitalnya. Sejauh pekerjaan yang baik dimungkinkan. Yang pasti, memang ada kekurangannya, dan pembersihan data sedang berlangsung. Bagaimana cara kita menyelesaikan ini, biarkan para pemimpin pemerintahan merenungkan hal itu. Mereka membuat keputusan untuk diri mereka sendiri yang bermanfaat bagi kita semua.

Dan sekarang mari kita ke yang lebih sulit dipahami - kita akan mengajarkan Alamat untuk membaca data yang tepat dari sumber kami. Untungnya, set data layanan pajak federal memiliki deskripsi siap pakai untuk struktur dokumen XML. Menurut deskripsi dari situs web FIAS yang menyertai data, kita akan memerlukan set data ADDROBJ yang, dalam kasus saya, sesuai dengan file AS_ADDROBJ_2_250_01_04_01_01.xsd

Selanjutnya, mari kita gunakan wizard skema XSD. Kami akan melakukan operasi di terminal:

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

Akibatnya, kami memiliki dua kelas yang sepenuhnya mencerminkan struktur XML alamat kami:

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 ]; } 

Dari seluruh daftar file XML di FIAS, kami hanya akan menggunakan file dengan nama wilayah, kota, dan jalan. Ketika saya sedang bersiap untuk publikasi, saya memilikinya:

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


Mari kita memasak beberapa boneka lada FIAS. Ini hanya persiapan untuk masa depan yang baik di masa depan. Pertama, kita akan mendapatkan set minimum awal. Ini adalah satu-satunya bahan yang kami butuhkan:

 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 ]; } 

Kami akan membuat objek yang memahami XML sebagai bahasa asli dengan menggunakan kelas dari pustaka sistem% XML.Reader:

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

Kami akan memberikan instruksi tentang siapa yang harus diambil, dan memintanya untuk mengabaikan sisanya. Kami akan mengambil satu porsi untuk pengujian.

Selanjutnya ... Korelasi / Baca, dll. ...

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

Maka bagian selanjutnya mudah: kita hanya membaca dan menyimpan.

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

Dan seterusnya, 3.722.548 kali untuk setiap operasi :-)

Itu bahkan lebih melelahkan dari sebelumnya. Itu sebabnya kami akan menambahkan metode kelas FIAS.AddressObject kami untuk mengimpor, berdasarkan pada perintah yang sama:

 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) } 

Kami akan menggunakan kekuatan eksokorteks komputer kami hanya dengan satu perintah di terminal :

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

gambar

Makan malam sudah siap, semuanya. Itu mBD, dan sekarang hidangan jadi, global dengan nama kota Rusia yang terverifikasi.

gambar

Dan, akhirnya, beberapa kata tentang apa yang harus dilakukan ketika 4TB tidak cukup. Dalam hal ini, kami menggunakan stream . Semuanya tercantum dalam dokumentasi. Anda dapat menggunakan biner atau karakter. Menyimpan dalam global juga dimungkinkan. Ini resepnya: ambil alirannya, potong-potong, dan tetapkan ke objek yang kita butuhkan untuk konsumsi.

Tidak ada cukup ruang di sini untuk lebih banyak tentang objek ObjectScript dan Python API yang indah. Itu akan menjadi cerita lain.
Berita baik: Gartner baru saja menyelesaikan pengumpulan tahunan penilaian pengguna nyata dan umpan balik dalam kategori DBMS dan menggunakan informasi ini untuk menerbitkan rangking DBMS terbaik 2019. AntarSistem CachΓ© dan AntarSistem IRIS Data Platform menerima peringkat tertinggi untuk "Pelanggan 'Pilihan. " Anda dapat memeriksa produk mana yang dipertimbangkan dan bagaimana mereka dinilai.
Perangkat Lunak Sistem Manajemen Basis Data Operasional Terbaik 2019 yang diulas oleh Pelanggan.

gambar

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


All Articles