QlikView وشقيقه الأصغر QlikSense من أدوات BI الرائعة التي تحظى بشعبية كبيرة في بلدنا وفي الخارج. في كثير من الأحيان ، تقوم هذه الأنظمة بحفظ النتائج "المتوسطة" لعملها - البيانات التي تصور "لوحات المعلومات" الخاصة بهم - في ما يسمى "ملفات QVD". غالبًا ما تستخدم ملفات QVD كمخزن رئيسي في عمليات ETL متعددة المراحل التي بنيت على أساس Qlik. ثم لدى البعض (على سبيل المثال ، أنا - أتعامل مع هندسة البيانات في الشركة) سؤالًا - هل من الممكن وكيفية استخدام هذه البيانات دون QlikView / QlikSense؟ أو آخر - وما هو موجود وهل صحيح أنه تم حسابه؟
QVD هو تنسيق ملف محسّن لـ QlikView / QlikSense (القراءة من كتابة المعلومات بواسطة هذه التطبيقات إلى ملفات بهذا التنسيق أسرع بكثير من الملفات بأي تنسيق آخر). هيكل هذا الملف غير موثق ومغطى بـ "كآبة الملكية" ، لا يوجد عمليا أي تطبيقات يمكن أن تعمل مع مثل هذه الملفات (قراءة وحتى كتابة أكثر). في هذه السلسلة من المقالات ، سأشارك تجربتي ومعرفتي العملية المكتسبة: أعرف كيف تعمل QVD ، يمكنني القراءة والكتابة مباشرة وبسرعة.
من سيكون مهتمًا بهذه المعلومات: أولاً وقبل كل شيء ، أولئك الذين يعملون مع QlikView / QlikSense ، وكذلك أولئك الذين (مثلي) يرغبون في استخدام البيانات المخزنة في ملفات QVD. وبطبيعة الحال ، للجميع فضولي.
يعتمد كل شيء مكتوب في هذه السلسلة على تجربتي الشخصية ، والتي ، بالطبع ، ليست "توثيق" أو "ضمان" (أن ملفاتك ستكون هي نفسها كما وصفتها بالضبط. أو أنها ستكون إلى الأبد ). لا يمكنني أيضًا ضمان أن أكون قد اكتشفت جميع الحالات - بالتأكيد قد تكون هناك ملفات تحتوي على شيء لم أصفه من قِبل لي (فقط لأنني لم أتطابق مع هذه الخيارات). ومع ذلك ، يجب أن أشير إلى أنه يتم فحص المعلومات على مجموعة كبيرة (عدة مئات) من الملفات التي تم إنشاؤها بواسطة أشخاص مختلفين من أنظمة مختلفة باستخدام إصدارات مختلفة من QlikView / QlikSense.
وقليلا حول كيفية القيام بذلك: لقد بدأت بمثال بسيط - مثال صغير مضمّن تم حفظه في QVD. علاوة على ذلك - تحليل الملف الثنائي ، جهود الدماغ ، الاختبارات والأخطاء. في المستقبل (سأتحدث عن هذا بمزيد من التفصيل في ختام السلسلة) ، تمكنت من قراءة وكتابة ملفات QVD ذات الحجم المتوسط (مئات الجيجابايت) بكفاءة عالية. كانت نقطة الانطلاق لرحلتي إلى عالم QVD هذا GitHub ، شكرًا جزيلاً للمؤلف (حاول الاتصال به - لا يستجيب).
ما هو هدفي (إلى جانب الفضول والرغبة في التحقق من صحة البيانات التي يعمل معها QlikView / QlikSense) ، كنت بحاجة إلى قراءة محتويات ملف QVD ، أي إعادة جدول علائقية بناءً عليه. على العكس من ذلك ، قم بتحميل بيانات الجدول العلائقية إلى QVD حتى يتمكن QlikView من تحميلها بشكل صحيح.
كيف أرى هذه السلسلة من المقالات
- مقدمة ، بنية الملف ، البيانات الوصفية (هذه المقالة)
- تخزين معلومات العمود
- تخزين معلومات الخط ، والإنجازات ، والخطط
هيكل الملف
يتم إنشاء ملف QVD بواسطة البرنامج النصي QlikView / QlikSense في عملية تحميل البيانات في ذاكرة التطبيق (نتيجة الأمر STORE) ويتوافق مع جدول QlikView / QlikSense واحد (علائقي). يتكون من جزأين
- نصية (بيانات التعريف) و
- ثنائي (الأعمدة والصفوف)
يتم تقديم البيانات الوصفية بتنسيق XML (سيتم تقديم مثال على ذلك أدناه) ، ويبدأ الجزء الثنائي مباشرة بعد النص ويتألف من كتلتين
- القيم الفريدة لجميع الأعمدة (الجدول المصدر)
- الصفوف (الجدول المصدر) التي تشير إلى قيم الأعمدة الفريدة

وبالتالي ، بالنسبة لجدول الأعمدة N ، سيحتوي الملف على كتل ثنائية N + 1. جميع أجزاء الملف "يتم لصقها بإحكام" وتذهب واحدة تلو الأخرى دون أي مواد مالئة و "ساق".
يحتوي ملف 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 لا تتغير من ملف إلى آخر.
سأعلق على أهم عناصر البيانات الوصفية.
QvBuildNo
رقم البنية لتطبيق QlikView / QlikSense الذي أنشأ ملف QVD.
CreatorDoc
كقاعدة عامة ، يحتوي على اسم ملف QVW الذي قام البرنامج النصي الخاص به بإنشاء ملف QVD. هذا المثال فارغ ، ربما بسبب استخدام الإصدار الشخصي.
CreateUtcTime
وقت إنشاء ملف QVD.
SourceCreateUtcTime و SourceFileUtcTime و SourceFileSize و StaleUtcTime
لم أشاهد الملفات التي سيتم فيها ملء هذه الحقول - للعقل المستفسر: ربما بعض الإعدادات مفقودة؟
TABLENAME
اسم الجدول في QlikView (انظر المثال أعلاه).
بالمناسبة ، عبارة "الحقل" و "العمود" هي مرادفات بالنسبة لي ، ولا تنزعج إذا استخدمتهما كليهما (سأحاول ألا أفعل ذلك ، ولكن لا يزال ...).
يتم تخزين المعلومات حول كل حقل في QVD عنه
FIELDNAME
اسم الحقل (مرة أخرى من حيث QlikView ، أي مع مراعاة "AS")
BitOffset، BitWidth، Bias
الآن ، دعنا نتخطى - هذه معلومات لـ "فك رموز السلاسل" ، سننظر في الجزء الثالث عند تعاملها مع السلاسل.
اكتب ، nDec ، UseThou ، Fmt ، ديسمبر ، أنت
مصممة بشكل جيد (وفقًا للأسماء) ، ولكن بلا فائدة من وجهة نظر تحقيق معلومات هدفي (لمزيد من التفاصيل ، انظر الجزء الثاني ، حيث سنتحدث عن الأعمدة). لماذا هو عديم الفائدة؟ - لا ترتبط علامة "النوع" بنوع البيانات المخزنة في الجزء الثنائي. من المستحيل استعادة نوع العمود منه (يبدو أنه قد يكون أسهل ، هناك علامة كتابة!). في 90٪ من الحالات ، ستكون قيمة هذه العلامة هي السلسلة UNKNOWN ...
في البيانات الوصفية حول الأعمدة ، لا تزال هناك مثل هذه البيانات (في البيانات الوصفية للمثال ، لا يرجع ذلك ، على ما يبدو ، إلى الحجم الصغير)
<Comment></Comment> <Tags> <String>$numeric</String> <String>$integer</String> </Tags>
لا يحتاج التعليق إلى تعليقات (بالمناسبة ، الملفات التي عملت بها فارغة 100٪ ...).
العلامات هي أيضا عديمة الفائدة (من وجهة نظر استعادة بنية الجدول) المعلومات. ولكن من خلاله يمكنك تخمين نوع المعلومات التي يتم تخزينها في العمود تقريبًا. سأتطرق إلى الكتابة بمزيد من التفاصيل في الجزء الثاني - عندما سأتحدث عن الأعمدة: هذا أمر مهم. ولكن أكثر تعقيدا قليلا مما أود.
NoOfSymbols
عدد الإدخالات في الجزء الثنائي المرتبطة بهذا العمود. كما نرى ، في مثالنا هو 5. المعلومات التي هي مهمة جدا لفك التشفير.
عوض
إزاحة كتلة البيانات في هذا العمود بالبايت بالنسبة لبداية الجزء الثنائي من الملف. أيضا مهم جدا.
طول
طول كتلة البيانات بالكامل لهذا العمود بالبايت. لاحظ أن التمثيل الثنائي لعنصر العمود (خلية الجدول) عمومًا له طول متغير (صف ، على سبيل المثال) ، لذلك لا يمكن حساب الطول ، يمكنك فقط أخذ هذه العلامة من هذه العلامة (الابتسامة).
ضغط
لا تملأ أبدًا (في البيانات التي عملت معها). ربما لا نستخدم هذا الخيار ...
RecordByteSize
حجم إدخال الصف بالبايت. يتم تمثيل جميع السلاسل في الكتلة الثنائية للسلاسل كمؤشر بت (المزيد في هذا الجزء الثالث) ، ويتكون فهرس البتات من صفوف من نفس الطول.
NoOfRecords
عدد الصفوف (في فهرس البت وفي الجدول المصدر).
عوض
إزاحة فهرس البت (كتلة بمعلومات السلسلة) بالبايت بالنسبة لبداية الجزء الثنائي من الملف.
طول
طول فهرس البت بالبايت.
في البيانات الوصفية حول الأوتار ، لا تزال هناك مثل هذه البيانات (مرة أخرى - مثال قصير لا يسمح لك برؤية كل شيء ، لكنه يتيح لك فهم المجمع)
<Lineage> <LineageInfo> <Discriminator>Provider=OraOLEDB.Oracle.1;Persist Security Info=True;Data Source=XXXX;Extended Properties=""</Discriminator> <Statement>LinkTable: LOAD SOURCE_NAME & '_' & 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=""</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>
أنا لم أتطرق إلى النقطة هنا كثيرًا ، إنها مفهومة إلى حد كبير (SELECTs الأصلية التي ولدت الجدول في QlikView) ، ما زلت لم أحسبها بعد (أحيانًا تتضاعف) ... (باستثناء واحدة - 100٪ لا توجد تعليقات (ابتسامة)) .
لتلخيص
- ملف QVD قائم بذاته (أي أنه يمكن تحليله بمعزل عن البيانات الأخرى)
- يتكون ملف QVD من أجزاء نصية (بيانات وصفية) وأجزاء ثنائية (أعمدة وفهرس بتات)
- بيانات التعريف هي XML مع دلالات واضحة
يحق للقارئ الفضولي أن يسأل هنا: "حتى الآن لم يسمع أي شيء جديد ، يمكن أخذ كل ما سبق وعرضه في رأس XML لملف QVD ... لقد كتب هذا بالفعل عدة مرات على شبكة الإنترنت المختلفة ، ما هو الجديد؟" هذا صحيح - الجزء الأول مخصص بالكامل تقريبًا للبيانات الوصفية. لكن هذه ليست النهاية.
ماذا بعد - في الجزء التالي ، سنبحث بالتفصيل بنية الجزء الثنائي من ملف QVD الذي يحتوي على معلومات حول الأعمدة (قيم فريدة لجميع أعمدة الجدول).