口袋里有microBIGDATA或FIAS
彼得·布鲁格(Peter Brueghel),《 纳税》 ,1640年剃须刀
上对象的最后一个条目走了。 我们将在战斗中继续侦察。 今天我们将讨论困难。 它不是关于BIG DATA的,但是它已经不方便使用-大量数据。 不是每个人都可以容纳整个RAM,但是有些人甚至不能容纳在磁盘上(没有足够的空间,但是有很多垃圾)。 我们的信任
FIAS数据库的名称是联邦地址信息系统的数据库。 5.5 GB存档。 并将其压缩为XML存档。 解压缩后,将有一个完整的53 GB(存储110 GB用于解压缩)。 而当您开始对其进行解析和转换时,那么110 GB的存储空间还不够。 大约需要的RAM数量也将是。
一切都会好起来的,但是您可以进一步挖掘。 有这样一个国际开源数据收集和系统化项目
-OpenAddresses 。 因此将会有更多的数据库。 当前地球上的覆盖面有很多白点,例如,俄罗斯几乎不存在。 存档大小为10 GB。
或一个相当著名的
OpenStreetMaps项目的数据库。 它是由志愿者根据维基百科构建的。 非常详细和多语言。 现在是一个压缩的XML的完整档案,大小为74 GB。
如果他们开始谈论地址,那么今天最好的安全搜索引擎DuckDuckGo会及时收到有关其过渡到Apple卡的意外消息 。 更确切地说,是在Apple MapKit JS上。 在我们的上下文中,最有趣的功能是“改进的地址搜索”。 苹果最好地努力收集和保护我们的数据吗? 有必要追踪...
因此,挑战。 如何将所有这些地址财富放入一个令人愉悦的存储库中使用,如何使您梦想一个免费的API(当然,在Python中),而又不让您的亲爱的人在未读的负载下窒息。 我们称它为MicroBigData-英文的mcBD或μBG:-)
在第二个(甚至第一个)开发人员的经济中,这个东西是一个地址目录,它也是一个地名目录,这是非常必要的。 而且当它正确规范,准备,清洁并由正确的机构记录在案时,这只是童话。 我们必须表示敬意,俄罗斯的税务服务正在做好其数字制作工作。 尽可能。 内部可能存在一些缺陷,并且数据清理仍在继续。 如何解决这个问题,让国家元首思考。 他们为自己和为我们所有人的利益做出决定。 顺便说一下,在下面的示例中发现了FIAS的一个错字。 结果不受影响。 我没有解决。 你会找到吗?
我不知道地址数据在您的项目中的相关性如何-这些都是区域,城市,街道。 但是,似乎没有一个项目能够为人们提供帮助。 那是寻找人或寄包裹给他的地址。 必须保存护照或任何其他文件的详细信息。 或者也许是建议参观的办公地点或景点的地址。 怎么办? 去哪儿
不考虑错误和重复项的最简单解决方案是包含简单字符串文字(它们是字符串常量,它们也是字符串)的原始对象。 让用户在其中输入下一个收到的条目。 这些对象能够保存自己-我们已经
通过了此操作 。
这样的对象例如在下面的类中描述。
直接来自教科书 ,尽管是美国的,但针对我们的俄罗斯现实进行了调整-而不是它们的ZIP,将有我们的postalCode。 我也将邮政编码替换为数字,但是为了单调起见,我留下了一个字符串。 任何立即识别一种语言(即ObjectScript)的人都可以得到鼓励。
Class Soviet.Address Extends %Persistent { Property streetName As %String; Property cityName As %String; Property areaName As %String; Property postalCode As %String; }
当然,许多人会感到愤怒,他们说一切都从物品的口袋里掏出来了(字面意思)。 在哪里可以看到物体,以便该物体在公共场所发光? 让我们这样离开吧,它太有说服力了,对任何学生来说都是可以理解的。
实际上,这就是所需要的。 填写字段。 存放在仓库中。 转移到其他对象上班。 继承给某人。 一切正常。 并存储!
但是必须说几句话,为什么这样做不值得。 我们的对象地址是什么? 为什么不能只是一组文本字符串? 想到的最明显的异议来自上下文-谁以何种形式和目的使用此地址? 尝试搁置您的编程思想,并想象一下“外国游客”,“历史学家”,“税务检查员”,“律师”等如何思考。
我认为,马上会出现许多其他问题和说明:使用哪种语言,存储和给出的编码方式,分类的时代,生效的法律或邮政文件? 城市是命名定居点还是什么? 甚至一条街道也可能变成林荫大道,小巷,大道或其他东西。 如何处理所有这些重要的实现细节?
以生活为例。 Google现在由Sundar Pichai经营。 他本人来自印度。 生于钦奈(又名钦奈)市。 还是在马德拉斯? 1996年,印第安人认为该城市的名称非常具有葡萄牙特色,并将泰米尔纳德邦(Tamil Nadu)的首都从马德拉斯(Madras)改名为金奈(Chennai)。 桑达尔和他的7200万同胞应该在电子文件中写些什么?
一般而言,整个科学都涉及这种应用的地名 。
所以问题开始了。 如何处理
时间和日期 ?
钱这么
明显吗? 地理坐标这么简单吗? 以及如何在您的代码中实现呢? 您可以在不降低抽象级别的情况下转移到选定的DBMS吗? 如何不陷入机器数据的原子类型并不断思考它们的重构? 在这里值得寻找原始或相反的声音API的来源。 闲暇时考虑一下。
简而言之,上下文是最重要的。 对象模型使我们能够通过封装“机器数据”和实现上下文相关的“实时”行为直接使用它。 根本不在表中列出的低级元组;-)
同时,让我们回到“原始”实现并使我们的生活复杂化。 首先,消除错误和重复。 也就是说,我们将寻找一种立即写入地址的方法。 同时,我们将帮助用户界面的开发人员在填写数据输入字段时为用户组织提示。
当两个人聚集在一个地方-文本和InterSystems IRIS数据平台时,开发人员就有机会在不离开机器的情况下进行全面部署。 例如,使用内置对象组件iKnow和iFind 。 这些分别是用于处理非结构化数据和全文本搜索的组件。 “开箱即用”支持俄语。
首先,我们将教地址从原始来源读取必要的数据。 幸运的是,联邦税收服务的数据集具有对XML文档结构的现成描述。 根据
FIAS网站数据附带的
描述 ,我们需要ADDROBJ数据集,在我的情况下,该数据集对应于文件AS_ADDROBJ_2_250_01_04_01_01.xsd
接下来,我们将使用XSD模板的系统转换器转换为%XML.Adaptor类的相应字段结构,这是由IRIS开发人员为我们准备的。 开头的百分号仅表示这是系统库中的类。
使用细节在文档中 。 我们将在终端中执行操作。
set xmlScheme = ##class(%XML.Utils.SchemaReader).%New() do xmlScheme.Process("http://localhost/AS_ADDROBJ_2_250_01_04_01_01.xsd")
可以在
Atelier IDE (在“工具”>“加载项”>“ XML模式向导”菜单中)获得相同的结果,也可以通过直接从程序代码对对象的相似请求获得相同的结果。

由于我们使用构造函数时没有指定参数,即用于放置结果类的包的名称,因此它们最终出现在Test包中。 从第二个命令可以看到,我通过Python的本地Web服务器提供了方案文件:
python3 -m http.server 80
您可以使用任何其他喜欢的http服务器。 或将文件上传到您的IRIS服务器并指出其直接路径。
因此,我们有两个类完全反映了可寻址XML的结构:
Test.AddressObjects /// Class Test.AddressObjects Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "AddressObjects"; Parameter XMLSEQUENCE = 1; /// Relationship Object As Test.Object(XMLNAME = "Object", XMLPROJECTION = "ELEMENT") [ Cardinality = many, Inverse = AddressObjects ]; }
测试对象 /// : 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; /// Property AOGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOGUID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property FORMALNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "FORMALNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property REGIONCODE As %String(MAXLEN = 2, MINLEN = 2, XMLNAME = "REGIONCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property AUTOCODE As %String(MAXLEN = 1, MINLEN = 1, XMLNAME = "AUTOCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property AREACODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "AREACODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property CITYCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "CITYCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property CTARCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "CTARCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property PLACECODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "PLACECODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property PLANCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "PLANCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property STREETCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "STREETCODE", XMLPROJECTION = "ATTRIBUTE"); /// Property EXTRCODE As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "EXTRCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property SEXTCODE As %String(MAXLEN = 3, MINLEN = 3, XMLNAME = "SEXTCODE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property OFFNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "OFFNAME", XMLPROJECTION = "ATTRIBUTE"); /// Property POSTALCODE As %String(MAXLEN = 6, MINLEN = 6, XMLNAME = "POSTALCODE", XMLPROJECTION = "ATTRIBUTE"); /// Property IFNSFL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "IFNSFL", XMLPROJECTION = "ATTRIBUTE"); /// Property TERRIFNSFL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "TERRIFNSFL", XMLPROJECTION = "ATTRIBUTE"); /// Property IFNSUL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "IFNSUL", XMLPROJECTION = "ATTRIBUTE"); /// Property TERRIFNSUL As %String(MAXLEN = 4, MINLEN = 4, XMLNAME = "TERRIFNSUL", XMLPROJECTION = "ATTRIBUTE"); /// OKATO Property OKATO As %String(MAXLEN = 11, MINLEN = 11, XMLNAME = "OKATO", XMLPROJECTION = "ATTRIBUTE"); /// OKTMO Property OKTMO As %String(MAXLEN = 11, MINLEN = 8, XMLNAME = "OKTMO", XMLPROJECTION = "ATTRIBUTE"); /// Property UPDATEDATE As %Date(XMLNAME = "UPDATEDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property SHORTNAME As %String(MAXLEN = 10, MINLEN = 1, XMLNAME = "SHORTNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property AOLEVEL As %Integer(XMLNAME = "AOLEVEL", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Property PARENTGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PARENTGUID", XMLPROJECTION = "ATTRIBUTE"); /// . . Property AOID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property PREVID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PREVID", XMLPROJECTION = "ATTRIBUTE"); /// Property NEXTID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "NEXTID", XMLPROJECTION = "ATTRIBUTE"); /// 4.0. Property CODE As %String(MAXLEN = 17, MINLEN = 0, XMLNAME = "CODE", XMLPROJECTION = "ATTRIBUTE"); /// 4.0 ( ) Property PLAINCODE As %String(MAXLEN = 15, MINLEN = 0, XMLNAME = "PLAINCODE", XMLPROJECTION = "ATTRIBUTE"); /// . . . /// 0 – /// 1 - Property ACTSTATUS As %Integer(XMLNAME = "ACTSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Property CENTSTATUS As %Integer(XMLNAME = "CENTSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// – (. OperationStatus): /// 01 – ; /// 10 – ; /// 20 – ; /// 21 – ; /// 30 – ; /// 31 - ; /// 40 – (); /// 41 – ; /// 42 - ; /// 43 - ; /// 50 – ; /// 51 – ; /// 60 – ; /// 61 – Property OPERSTATUS As %Integer(XMLNAME = "OPERSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// 4 ( ) Property CURRSTATUS As %Integer(XMLNAME = "CURRSTATUS", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Property STARTDATE As %Date(XMLNAME = "STARTDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property ENDDATE As %Date(XMLNAME = "ENDDATE", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property NORMDOC As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "NORMDOC", XMLPROJECTION = "ATTRIBUTE"); /// Property LIVESTATUS As %xsd.byte(VALUELIST = ",0,1", XMLNAME = "LIVESTATUS", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// : /// 0 - /// 1 - ; /// 2 - - 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 ]; }
在FIAS中的xml文件的整个列表中,我们将仅使用带有地区,城市和街道名称的文件。 在准备出版物时,我有以下几点:
AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML
文件大小既不大也不小,但几乎为3 GB。 您不会使用普通文本工具打开它-它们不会消化此大小。
顺便说一句,InterSystems IRIS中的字符串文字(String类型)的最大长度不超过3,641,144个字符。 也就是说,直接下载文件或将URL下载到其中将失败。 其他限制可以在文档中找到。 要处理大量数据,可以使用没有这种长度限制的数据流(流)。
让我们看看我们得到了什么?
烹饪FIAS酿胡椒。 这只是美好未来的准备。 首先,我们得到初始最小集。 我们只需要这些成分:
Class FIAS.AddressObject Extends (%Persistent, %XML.Adaptor) [ ProcedureBlock ] { Parameter XMLNAME = "Object"; Parameter XMLSEQUENCE = 1; /// Property AOGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "AOGUID", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property OFFNAME As %String(MAXLEN = 120, MINLEN = 1, XMLNAME = "OFFNAME", XMLPROJECTION = "ATTRIBUTE"); /// Property POSTALCODE As %String(MAXLEN = 6, MINLEN = 6, XMLNAME = "POSTALCODE", XMLPROJECTION = "ATTRIBUTE"); /// Property SHORTNAME As %String(MAXLEN = 10, MINLEN = 1, XMLNAME = "SHORTNAME", XMLPROJECTION = "ATTRIBUTE") [ Required ]; /// Property AOLEVEL As %Integer(XMLNAME = "AOLEVEL", XMLPROJECTION = "ATTRIBUTE", XMLTotalDigits = 10) [ Required ]; /// Property PARENTGUID As %String(MAXLEN = 36, MINLEN = 36, XMLNAME = "PARENTGUID", XMLPROJECTION = "ATTRIBUTE"); /// . . 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")
然后是如何获取原始microbd文件的各种方法。 如果方便,可以将其放在资源库旁边-在IRIS服务器的文件系统中本地。 或者,例如在我的示例中,要求通过HTTP发送。 还有一个更通用的选择,关于它,下面会有几个词。
set url="http://localhost/AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML" write reader.OpenUrl(url)
重要! 此刻,大多数将自己树立榜样的人会感到非常糟糕。 系统将返回快乐的“ 1”(一切正常),而不是返回“ 0¸STORE ...”。 而且它不会讨好。 也就是说,看似微库的文件不是很微,因此不适合我们的对象。 为他分配的内存不足。 可解决的? 当然可以 IRIS数据平台允许您在RAM中创建高达4 TB的对象。 那出了什么问题? 默认情况下,每个对象的系统设置都设置为256 MB。 我们还需要更多。 请记住,这些是RAM要求。 您的计算机/服务器上是否有足够的库存?
我们需要安装多大的内存才能凭经验安装这个巨大的内存-近10 GB。 您需要在设置(菜单>配置内存>每个进程的最大内存(KB))中或通过
$ ZSTORAGE系统变量 (以千字节为单位)指定什么:
set $ZSTORAGE=10000000
是否启动了具有必要内存设置的新进程? 然后,一切变得更简单-我们阅读并保存。
还有一个替代的(可能是首选的)选项-
使用 %XML.Reader类
的UsePPGHandler属性 ,该
属性允许您不将XML存储在内存中并且可以使用标准内存设置。
set reader = ##class(%XML.Reader).%New() set reader.UsePPGHandler = 1
更多...相关/阅读等 ...
do reader.Next(.object) do object.%Save()
因此,每个操作3,722,548次:-)
这很累。 因此,我们根据刚刚显示的命令为FIAS.AddressObject类添加导入方法:
ClassMethod Import() { // XML Set reader = ##class(%XML.Reader).%New() // XML Set status = reader.OpenURL("http://localhost/AS_ADDROBJ_20190106_90809714-fe22-45b2-929c-52bd950963e0.XML") If $$$ISERR(status) {Do $System.Status.DisplayError(status)} // Do reader.Correlate("Object","FIAS.AddressObject") // While (reader.Next(.object,.status)) { Set status = object.%Save() If $$$ISERR(status) {do $System.Status.DisplayError(status)} } // , If $$$ISERR(status) {Do $System.Status.DisplayError(status)} }
让我们使用计算机exocortex的强大功能-
终端中只有一个命令:
do ##class(FIAS.AddressObject).Import()

我请大家到桌旁。 那里有MCD,现在已经准备好以经过验证的俄罗斯城市和重量名称的全球形式的成品。

最后几句话是关于何时4TB还不够。 在这种情况下,
我们将按照流 (或您愿意的流)进行
跟踪 。 该文档放在架子上。 您可以二进制,也可以符号。 也不禁止在全球范围内存储。 诀窍是这样的:我们将一条溪流切成小段,然后将其分配给需要消耗的物体。
此外,关于Python中漂亮的可寻址ObjectScript对象和API不合适。 会有一个单独的故事。
宜人:Gartner刚刚完成了DBMS类别的年度实际用户评级和评论年度收集,并在此基础上发布了他对2019年最佳DBMS的评级。 InterSystemsCaché和InterSystems IRIS数据平台产品获得了最高的消费者选择评价。 从您选择的人以及您的评分方式, 您可以窥视自己 。
客户评选的2019年最佳运营数据库管理系统软件
