QVD文件-里面有什么

QlikView和他的弟弟QlikSense是出色的BI工具,在我国和国外都很流行。 通常,这些系统将工作的“中间”结果(可视化其“仪表盘”的数据)保存到所谓的“ QVD文件”中。 在基于Qlik的多阶段ETL流程中,通常将QVD文件用作主要存储。 然后,有些人(例如,我-我在公司从事数据工程工作)提出了一个问题-如果没有QlikView / QlikSense,是否可能以及如何使用这些数据? 还是另一个-那里是什么,计数是正确的吗?


QVD是针对QlikView / QlikSense优化的文件格式(通过这些应用程序从写入信息读取到该格式的文件比读取任何其他格式的文件要快得多)。 该文件的结构是未记录的,并带有“专有权的阴郁”,实际上,没有任何应用程序可以使用此类文件(读取甚至是写入)。 在本系列文章中,我将分享我的经验和实践知识:我知道QVD的工作原理,可以直接,快速地对其进行读写。


谁会对这些信息感兴趣:首先,那些使用QlikView / QlikSense的人以及那些(像我一样)想使用QVD文件中存储的数据的人。 并且,当然,对每个人都有好奇心。


本系列中的所有内容均基于我的个人经验,当然,这不是“文档”或“保证书”(您的文件将与我所描述的完全相同,或者将永久存在) ) 我也不能保证我能找到所有情况-肯定会有一些文件包含我未描述的内容(如果仅仅是因为我没有遇到过此类选项)。 但是,我必须注意,信息是在由不同系统的不同人员使用不同版本的QlikView / QlikSense创建的大量文件(数百个)中检查的。


以及一些有关如何执行此操作的信息:我从一个简单的示例开始-一个保存在QVD中的小型内联示例。 进一步-二进制文件,大脑工作,测试和错误的分析。 展望未来(我将在本系列的结论中更详细地讨论这一点),我能够相当高效地读写中等大小(数百GB)的QVD文件。 我进入QVD世界的起点是这个GitHub ,非常感谢作者(试图与他联系-没有回应)。


我的目标是什么(好奇心和验证QlikView / QlikSense使用的数据的正确性的愿望),我需要读取QVD文件的内容,即 重新基于它创建一个关系表。 相反,将关系表数据上传到QVD,以便QlikView可以正确加载它。


我如何看这一系列文章


  • 简介,文件结构,元数据(本文)
  • 信息的存储
  • 存储行信息,成就,计划

档案结构


QVD文件是由QlikView / QlikSense脚本在将数据加载到应用程序内存(STORE命令的结果)的过程中创建的,并且对应于一个(关系)QlikView / QlikSense表。 它由两部分组成


  • 文字(元数据)和
  • 二进制(列和行)

元数据以XML表示(下面将给出一个示例),二进制部分在文本之后立即开始,由两个块组成


  • 所有列的唯一值(源表)
  • 引用唯一列值的行(源表)

档案结构


因此,对于N列的表,文件将包含N +1个二进制块。 锉刀的所有部分都“紧紧地粘在一起”,并且一个接一个地接下去,没有任何填充物和“小腿”。


元数据(XML)


QVD文件包含许多元数据-“关于数据的数据”。 这几乎是自给自足的,请自行判断,这是元数据中内容的简短列表(我将在下面更详细地描述它们):


  • 生成文件的软件版本
  • 文件创建日期和时间
  • QlikView / QlikSense文件,其脚本导致了文件的创建
  • 生成QVD文件的脚本源代码
  • 表名
  • 列信息(名称,类型,唯一值的数量)
  • 行数

元数据以文本形式存储在文件中,并且可以在任何可以文本形式显示文件的程序中看到(嗯,几乎任何……都不怕大文件)。 就个人而言,我会着眼于元信息,这很方便。
在下面的演示中,我将使用测试表(我使用QlikView语法,但我认为这很容易猜想):


SET NULLINTERPRET =<sym>; tab1: LOAD * INLINE [ ID, NAME 123.12,"Pete" 124,12/31/2018 -2,"Vasya" 1,"John" <sym>,"None" ]; 

我将以该板的元数据为例


 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <QvdTableHeader> <QvBuildNo>7314</QvBuildNo> <CreatorDoc></CreatorDoc> <CreateUtcTime>2019-04-03 06:24:33</CreateUtcTime> <SourceCreateUtcTime></SourceCreateUtcTime> <SourceFileUtcTime></SourceFileUtcTime> <SourceFileSize>-1</SourceFileSize> <StaleUtcTime></StaleUtcTime> <TableName>tab1</TableName> <Fields> <QvdFieldHeader> <FieldName>ID</FieldName> <BitOffset>0</BitOffset> <BitWidth>3</BitWidth> <Bias>-2</Bias> <NumberFormat> <Type>0</Type> <nDec>0</nDec> <UseThou>0</UseThou> <Fmt></Fmt> <Dec></Dec> <Thou></Thou> </NumberFormat> <NoOfSymbols>4</NoOfSymbols> <Offset>0</Offset> <Length>40</Length> </QvdFieldHeader> <QvdFieldHeader> <FieldName>NAME</FieldName> <BitOffset>3</BitOffset> <BitWidth>5</BitWidth> <Bias>0</Bias> <NumberFormat> <Type>0</Type> <nDec>0</nDec> <UseThou>0</UseThou> <Fmt></Fmt> <Dec></Dec> <Thou></Thou> </NumberFormat> <NoOfSymbols>5</NoOfSymbols> <Offset>40</Offset> <Length>37</Length> </QvdFieldHeader> </Fields> <Compression></Compression> <RecordByteSize>1</RecordByteSize> <NoOfRecords>5</NoOfRecords> <Offset>77</Offset> <Length>5</Length> </QvdTableHeader> 

我对QVD的经验表明,XML结构在文件之间不会改变。


我将评论最重要的元数据元素。


一般资讯


QvBuild号


生成QVD文件的QlikView / QlikSense应用程序的内部版本号。


创作者文档


通常,它包含QVW文件的名称,该文件的脚本生成了QVD文件。 本示例为空白,可能是因为使用了个人版。


CreateUtcTime


QVD文件创建时间。


SourceCreateUtcTime,SourceFileUtcTime,SourceFileSize,StaleUtcTime


我不知道要填充这些字段的文件-怀疑的是:也许缺少某些设置?


表名


QlikView中表的名称(请参见上面的示例)。


有关字段(列)的信息


顺便说一句,“ field”和“ column”这两个词对我来说是同义词,如果我同时使用这两个词,请不要惊慌(我会尽量不要这样做,但仍然...)。


有关每个字段的信息存储在QVD中,有关


栏位名称


字段名称(同样以QlikView表示,即考虑到“ AS”)


BitOffset,BitWidth,偏置


现在,让我们跳过-这是“解码字符串”的信息,我们将在第三部分中考虑何时处理字符串。


类型,nDec,UseThou,Fmt,Dec,Thou


构思很好(按名称判断),但从实现我的目标信息的角度来看绝对没有用(有关更多详细信息,请参阅第二部分,我们将在此讨论专栏)。 为什么没用? -标签“类型”与二进制部分中存储的数据类型不相关。 无法从中还原列的类型(看起来很容易,有一个Type标记!)。 在90%的情况下,此标签的值将为字符串UNKNOWN ...


在有关列的元数据中,仍然存在此类数据(在示例的元数据中,显然不是由于大小较小)


 <Comment></Comment> <Tags> <String>$numeric</String> <String>$integer</String> </Tags> 

该注释不需要注释(顺便说一下,我使用的文件是100%空的...)。


标签也是无用的(从恢复表结构的角度来看)信息。 但是从中您可以大致猜测出该列中存储了哪种类型的信息。 在第二部分中,当我谈论列时,我将详细介绍打字:这很重要。 但是比我想要的要复杂一些。


NoOfSymbols


二进制部分与此列相关的条目数。 如我们所见,在我们的示例中为5。信息对于解密非常重要。


偏移量


相对于文件二进制部分的开头,此列的数据块的偏移量(以字节为单位)。 也很重要。


长度


此列的整个数据块的长度,以字节为单位。 请注意,列元素(表单元格)的二进制表示形式通常具有可变的长度(例如,行),因此无法计算长度,您只能从此标记中获取(微笑)。


字符串信息


压缩方式


永远不要填写(在我处理过的数据中)。 也许我们没有使用此选项...


记录字节大小


行条目的大小(以字节为单位)。 所有字符串在二进制二进制块中均表示为位索引(在第三部分中对此有更多说明),位索引由相同长度的行组成。


NoOfRecords


行数(在位索引和源表中)。


偏移量


位索引(带有字符串信息的块)相对于文件二进制部分开头的偏移量(以字节为单位)。


长度


位索引的长度(以字节为单位)。


在有关字符串的元数据中,仍然存在此类数据(同样,一个简短的示例无法让您看到所有内容,但可以让您了解复杂的内容)


 <Lineage> <LineageInfo> <Discriminator>Provider=OraOLEDB.Oracle.1;Persist Security Info=True;Data Source=XXXX;Extended Properties=&quot;&quot;</Discriminator> <Statement>LinkTable: LOAD SOURCE_NAME &amp; '_' &amp; SOURCE_ID as SYSKEY, HID_PARTY;SQL SELECT * FROM UNITED_VIEW</Statement> </LineageInfo> <LineageInfo> <Discriminator>Provider=OraOLEDB.Oracle.1;Persist Security Info=True;Data Source=XXXX;Extended Properties=&quot;&quot;</Discriminator> <Statement>SQL SELECT * FROM UNITED_VIEW</Statement> </LineageInfo> <LineageInfo> <Discriminator>STORE - \\xxx.ru\mfs\SPECIAL\Qlikview\QVData\LinkTable.qvd (qvd)</Discriminator> <Statement></Statement> </LineageInfo> </Lineage> <Comment></Comment> 

我在这里不会太过分,这是可以理解的(在QlikView中生成表的原始SELECT),我仍然没有弄清楚(有时它们加倍了)...(除了-100%没有评论(微笑))。 。


总结一下


  • QVD文件是独立的(即可以与其他数据隔离地进行分析)
  • QVD文件由文本(元数据)和二进制(列和位索引)部分组成
  • 元数据是具有清晰语义的XML

一个好奇的读者有权在这里问:“到目前为止,还没有什么新的说法,以上所有内容都可以在QVD文件的XML标头中获取和查看...这已经在不同的Internet上写过很多遍了,新颖性是什么?” 是的-第一部分几乎完全致力于元数据。 但这还不是终点。


接下来是什么- 在下一部分中,我们将详细检查QVD文件二进制部分的结构,该文件包含有关列的信息(表中所有列的唯一值)。

Source: https://habr.com/ru/post/zh-CN454302/


All Articles