Mục tiêu của XGrind đó là thực hiện hiệu quả truy vấn tài liệu nén. Vì vậy cần thiết phải có một giản đồ nén phi ngữ cảnh context-free compression schema , tức là một giản đồ nén mà trong đó mỗi chuỗi trong tài liệu được gán một mã code độc lập về vị trí của nó trong tài liệu. Tính năng này cho phép xác định vị trí xuất hiện của một chuỗi bất kỳ một cách trực tiếp trong tài liệu nén mà không cần phải giải nén tài liệu.
Quá trình nén phi ngữ cảnh không thể thực hiện được với các thuật toán động (adaptive algorithms như LZ77 vì mã code được gán cho một mục dữ liệu data item phụ thuộc vào toàn bộ nội dung đã xuất hiện trước đó, nghĩa là khi thực hiện một truy vấn cho một chuỗi thì phải giải nén toàn bộ nội dung phía trước nó. Mặt khác, quá trình nén phi ngữ cảnh có thể thực hiện được với các phiên bản tĩnh non-adaptive của thuật toán Huffman và mã hóa số học Arithmetic Coding [12]). XGrind sử dụng thuật toán non-adaptive Huffman. Để hỗ trợ cho tính năng non-adaptive phải thực hiện hai bước chuyển đổi tài liệu XML: bước thứ nhất thu thập thống kê và bước thứ hai thực hiện quá trình mã hóa.
XGrind sử dụng một bảng phân bổ tần số riêng biệt cho mỗi phần tử hoặc thuộc tính không liệt kê bởi vì các dữ liệu thuộc về cùng một phần tử hay một thuộc tính thường có liên quan về mặt ngữ nghĩa và được dự kiến là sẽ có sự phân bố giống nhau.
Với lược đồ phi ngữ cảnh, các truy vấn có thể thực hiện trên tài liệu nén mà không cần giải nén toàn bộ tài liệu. Chính xác hơn là, các truy vấn tìm kiếm chính xác exact-match khóa tìm kiếm là một giá trị cụ thể và tìm kiếm theo tiền tố prefix-match khóa tìm kiếm là một tiền tố của các giá trị dữ liệu được thực hiện hoàn toàn trực tiếp trên tài liệu nén. Trong khi đó, tìm kiếm theo phạm vi range-match khóa tìm kiếm bao phủ một loạt các giá trị dữ liệu hoặc tìm kiếm từng phần partial-match khóa tìm kiếm là một chuỗi con của các giá trị dữ liệu lại yêu cầu quá trình giải nén thực hiện ngay nhanh chóng chỉ trên các giá trị của phần tử hoặc thuộc tính mà là một phần của biểu thức truy vấn.
3.2.3. Nén đ ng cấu (Homomorphic Compression)
Tính năng nổi bật của chương trình nén XGrind là tài liệu đầu ra của nó vẫn giữ nguyên cấu trúc giống như tài liệu đầu vào. Thực tế, tài liệu nén XML có thể được hiển thị như tài liệu XML gốc với thẻ, giá trị của phần tử hay thuộc tính được thay thế với các mã
code tương ứng của chúng. Thứ nhất, điều này rất thuận lợi cho quá trình sử dụng các kỹ thuật phân tích, truy vấn của tài liệu XML gốc cũng được áp dụng để xử lý các tài liệu nén. Thứ hai là chỉ mục có thể được thiết lập trong các tài liệu nén tương tự như cách thức đã được thiết lập trong tài liệu XML thông thường. Thứ ba là quá trình cập nhật đối với tài liệu XML có thể được thực hiện trực tiếp trên phiên bản nén. Cuối cùng, một phiên bản nén có thể kiểm tra tính hợp lệ của nó bằng cách sử dụng DTD mà không cần đến bất kỳ quá trình giải nén nào được minh họa bởi thuộc tính sau đây:
Cho một tài liệu XML X mà hợp lệ đối với một DTD D, hD là đồng cấu trong quá trình xác định lược đồ mã hóa XGrind cho siêu dữ liệu meta-data và các giá trị thuộc tính loại liệt kê. hD(D) là ký hiệu của DTD được nén và hD(X) là ký hiệu của tài liệu XML được nén. Thuộc tính sau đây là một kết quả của quá trình “phi ngữ cảnh” (context freeness) của lược đồ nén và tính chất bán cấu trúc đầu ra: X là hợp lệ với D khi và chỉ khi hD(X) hợp lệ với hD(D).
Nói cách khác, tài liệu nén có tính hợp lệ đối với DTD nén của nó.
3.2.4. Kiến trúc của XGrind
Kiến trúc của bộ nén XGrind được mô tả trong hình 3.3 bao gồm các thành phần chính sau:XML Parser, DTD Parser, XGrind Kernel, Enum-Encoder, Huffman-Encoder và XML- Gen.
XGrind Kernel là thành phần trung tâm của chương trình nén. Nó bắt đầu bằng việc triệu gọi bộ phân tích DTD DTD Parser dùng để phân tích cú pháp DTD của tài liệu XML, sau đó là quá trình khởi tạo các bảng tần số frequency tables cho từng phần tử hoặc thuộc tính không liệt kê, và sinh ra một bảng biểu tượng symbol table cho thuộc tính thuộc loại liệt kê. Tiếp theo, XGrind Kernel gọi tới bộ phân tích cú pháp XML XML Parser), quét tài liệu XML và sinh ra tập hợp các bảng tần số cho từng phần tử hoặc thuộc tính không liệt kê. Bộ phân tích cú pháp XML được XGrind Kernel gọi lần thứ hai để thiết lập một dạng thẻ bài hóa tokenized form cho thẻ, thuộc tính, giá trị của tài liệu XML. XGrind Kernel sẽ dựa vào loại của từng thẻ bài mà triệu gọi các bộ mã hóa tương ứng bao gồm bộ mã hóa liệt kê Enum-Encoder) và bộ nén Huffman Huffman-Compressor).
ộ mã h a liệt kê (Enum-Encoder) được sử dụng cho siêu dữ liệu meta-data và các hạng mục dữ liệu thuộc loại liệt kê. Mỗi thẻ bắt đầu của một phần tử được mã hóa bằng ký tự “T” được theo sau bởi một định danh duy nhất - ID. Tất cả các thẻ kết thúc được mã hóa bằng ký tự “/”. Tên các thuộc tính được mã hóa bằng ký tự “A” theo sau bởi một định danh duy nhất – ID. Các giá trị thuộc tính loại liệt kê được mã hóa bằng cách sử dụng thông tin bảng biểu tượng symbol table .
ộ nén Huffman (Huffman-Compressor) được sử dụng cho các hạng mục dữ liệu không liệt kê. Module này cài đặt lược đồ nén mã hóa non-adaptive Huffman. Nó mã hóa mỗi giá trị phần tử hoặc thuộc tính dựa vào cây Huffman mà được xây dựng từ bảng tần số tương ứng của nó.
Đầu ra đã được nén bởi các bộ mã hóa ở trên, cùng với các bảng tần số và bảng biểu tượng được gọi là CIR Compressed Internal Representation của chương trình nén và được cung cấp cho XML-Gen. XML-Gen sẽ chuyển đổi CIR thành một tài liệu XML nén bán cấu trúc.
Hình 3.3: Kiến trúc của bộ nén XGrind [15]
Ví dụ 3.11: Xét một phần nội dung của tài liệu Student.xml có nội dung như sau: <!--student.xml -->
<STUDENT rollno = "604100418"> <NAME>Pankaj Tolani</NAME> <YEAR>2000</YEAR>
<PROG>Master of Engineering</PROG> <DEPT name = "Computer Science"> </STUDENT>
Ví dụ 3.12: DTD của tài liệu XML trong ví dụ 3.11 như sau: <!-- DTD for the Student database -->
<!ELEMENT STUDENT (NAME, YEAR, PROG, DEPT)> <!ATTLIST STUDENT rollno CDATA #REQUIRED> <!ELEMENT NAME (#PCDATA)>
<!ELEMENT YEAR (#PCDATA)> <!ELEMENT PROG (#PCDATA)> <!ELEMENT DEPT EMPTY>
<!ATTLIST DEPT name (Computer_Science | Electrical_Engineering . . . | Physics | Chemistry) >
Ví dụ 3.13: Khung nhìn tóm lược về tài liệu XGrind như sau: T0 A0 nahuff(604100418) T1 nahuff(Pankaj Tolani)/ T2 nahuff(2000) / T3 nahuff(Master of Engineering)/ T4 A1 enum(Computer_Science)/ /
Xem xét một đoạn tài liệu XML trong ví dụ 3.11 minh họa một cơ sở dữ liệu sinh viên và DTD của nó được biểu diễn trong ví dụ 3.12. Ta thấy có năm phần tử là STUDENT, NAME, YEAR, PROG VÀ DEPT. Phần tử STUDENT có một thuộc tính rollno, trong khi DEPT có một thuộc tính loại liệt kê là name.
Trong ví dụ 3.13, thẻ STUDENT được mã hóa là T0, NAME là T1, YEAR là T2, PROG là T3 và DEPT là T4. Tất cả các thẻ kết thúc đều được mã hóa là “/”. Các thuộc tính rollno và name lần lượt được mã hóa là A0 và A1. ID của các phần tử hay thuộc tính và thuộc tính name của phần tử DEPT được xác định bởi bộ phân tích cú pháp DTD trong bước chuyển đầu tiên. nahuff s biểu thị đầu ra của bộ nén Huffman cho dữ liệu đầu vào s, trong khi enum s biểu thị đầu ra của bộ mã hóa liệt kê cho dữ liệu đầu vào s, trong đó s là giá trị loại liệt kê của thuộc tính.
3.3. XAUST
3.3.1. Tổng quan về XAUST
XAUST thuộc nhóm kỹ thuật nén XML không truy vấn và phụ thuộc vào thông tin lược đồ. Bộ nén XML XAUST chuyển đổi thông tin lược đồ DTD thành một tập hợp máy tự động hữu hạn xác định Deterministic Finite Automata - DFA , mỗi phần tử trong DTD sẽ có một DFA. Mỗi transition được gán nhãn bởi một phần tử và hành động action được kết hợp với một transition được gọi đến một bộ mô phỏng simulator cho DFA của phần tử đang được gán nhãn. XAUST nhóm tất cả dữ liệu trong cùng một phần tử vào trong một
container duy nhất và sử dụng bộ nén số học số 4 arithmetic order-4 compressor để nén. Bởi vì sử dụng thông tin lược đồ DTD, XAUST có khả năng tìm, kiểm tra cấu trúc của tài liệu và có khả năng dự đoán chính xác các biểu tượng mong đợi.
Các thành phần cơ bản của XAUST bao gồm: mã hóa số học và máy tự động hữu hạn xác định.
3.3.2. Mã h a số học và mô hình ngữ cảnh hữu hạn 3.3.2.1. Mã h a số học (Arithmetic Coding)
Mã hóa số học không thay thế các kí hiệu đầu vào bằng các từ mã riêng biệt. Thay vào đó, nó xử lý luồng ký tự đầu vào và thay thế nó bằng một từ mã duy nhất ở đầu ra. Đầu ra của mã hóa số học là một số thực lớn hơn 0 và nhỏ hơn 1. Số này là duy nhất và có thể được giải mã để tạo lại chính xác luồng các kí hiệu đầu vào. Mã hóa số học bắt đầu hoạt động của nó bằng việc phân chia trong khoảng giữa 0 và 1, dựa vào sự phân bố xác suất xuất hiện của kí hiệu trong mô hình đã được xây dựng. Khoảng này sẽ được tính toán lại sau khi có một kí hiệu được mã hóa.
3.3.2.2. Mô hình ngữ cảnh hữu hạn (Finite Context Modeling)
Trong một lược đồ ngữ cảnh hữu hạn, xác suất của mỗi biểu tượng hay kí hiệu được tính toán dựa trên ngữ cảnh mà biểu tượng xuất hiện trong đó. Ngữ cảnh chỉ là những biểu tượng mà đã được xuất hiện trước đó. Mô hình là một tập hợp các bảng đếm tần suất cho mỗi ngữ cảnh. Khi gặp một biểu tượng, số đếm tần suất sẽ được cập nhật vào trong bảng. Số đếm tần suất được sử dụng để tính xác suất và lược đồ tương ứng khi mỗi biểu tượng được quét qua. Thứ tự của mô hình tham chiếu đến số lượng các biểu tượng đã xuất hiện trước đó và tạo lên một ngữ cảnh. Trong một mô hình có thứ tự k, cả hai bộ nén và bộ giải nén đều bắt đầu cùng với một mô hình. Bộ nén mã hóa biểu tượng với một mô hình đã tồn tại và sau đó cập nhật lại mô hình cho mô hình mới. Bộ giải nén tương tự giải mã một biểu tượng bằng cách sử dụng mô hình đã có và sau đó cũng cập nhật lại mô hình. Ta thấy rằng, quá trình cập nhập lại mô hình và lưu các bảng đếm tần suất là một quá trình tốn kém, tiêu tốn một số lượng lớn không gian bộ nhớ. Điều này làm cho mã hóa số học chậm hơn các lược đồ dựa trên từ điển như Ziv-Lempel.
3.3.3. Máy tự động hữu hạn xác định
Hình 3.4: DFA của phần tử card trong ví dụ 3.14 Ví dụ 3.14: Xem xét một DTD được định nghĩa như sau:
<!DOCTYPE addressBook[
<!ELEMENT addressBook (card*)>
<!ELEMENT card ((name | (givenName, familyName)), email, note?)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT givenName (#PCDATA)> <!ELEMENT familyName (#PCDATA)> <!ELEMENT email (#PCDATA)>
<!ELEMENT note (#PCDATA)> ]>
Ví dụ 3.15: Một tài liệu xml tương ứng với DTD trong ví dụ 3.14. <addressBook> <card> <givenName>Hariharan</givenName> <familyName>Iyer</familyName> <email>hari@gmail.com</email> </card> <card> <name>Priti Shankar</name> <email>priti@gmail.com</email> <note>Hariharan’s advisor</note> </card> </addressBook>
Trong hình 3.4, có hai loại trạng thái trong máy tự động: có nhiều transition đầu vào và chỉ có một transition đầu ra duy nhất. Các biểu tượng mà được gán nhãn cho transition đầu ra duy nhất không phải mã hóa vì xác suất của chúng là 1. Do đó quá trình mã hóa số học các biểu tượng chỉ cần được thực hiện tại các trạng thái state có nhiều hơn một transition đầu ra. Phần tử mà có thuộc tính #PCDATA sẽ gọi đến một bộ mã hóa số học. Bộ mã số học này sẽ sử dụng một mô hình chung cho tất cả các thể hiện của thuộc tính đó và mã hóa chúng với cùng một tập hợp các bảng tần số.
Quá trình hoạt động của máy tự động được thực hiện theo trình tự như sau: - Nhập DFA của phần tử.
- Nếu chỉ có một cạnh transition ra khỏi trạng thái state của một phần tử thì không làm gì cả.
- Nếu phần tử có một thuộc tính #PCDATA thì mã hóa chuỗi các biểu tượng ký hiệu bằng cách sử dụng bảng tần số được kết hợp với phần tử đó.
- Nếu phần tử có nhiều hơn một cạnh transition ra khỏi một trạng thái state của phần tử thì sử dụng bộ mã hóa số học cho trạng thái đó và chuyển đến trạng thái bắt đầu của DFA cho phần tử đó.
Chú ý: XAUST sử dụng một bộ chứa container chung cho tất cả dữ liệu mà được kết hợp với mỗi phần tử.
Ví dụ 3.16: Xét phần tử A được mô tả như sau: <!ELEMENT A ((B | C), D)>
Ta thấy, phần tử D sẽ không phải mã hóa, tuy nhiên vẫn phải mã hóa cho phần tử B và C.
3.3.4. Quá trình nén và giải nén sử dụng XAUST
Trạng thái của bộ nén là một cặp element, state trong đó element biểu diễn phần tử hiện tại mà DFA XAUST của nó đi qua và sate là trạng thái của DFA. Giả sử rằng state hiện tại của bộ mã hóa Encoder là i, j . Khi gặp một thẻ mở cho phần tử k trong tài liệu, cặp trạng thái hiện tại của bộ mã hóa Encoder được lưu trữ trong stack và DFA cho phần tử k được nhập vào. Trạng thái mới của bộ mã hóa Encoder bây giờ là k, 0 . Khi gặp phải thẻ đóng của phần tử k, stack bị pop và trạng thái mới của bộ mã hóa Encoder là i, j+1 . Mỗi trạng thái có một mô hình số học mà nó được sử dụng để mã hóa trạng thái tiếp theo.
Ví dụ 3.17: Xét phần tử A được mô tả như sau: <!ELEMENT A ((#PCDATA | B)*)>
Trong ví dụ 3.17, có hai transition cho trạng thái bắt đầu của DFA cho phần tử A. Một transition triệu gọi mô hình số học cho #PCDATA. Một transition khác triệu gọi DFA cho phần tử B sau khi đẩy push trạng thái hiện tại vào trong stack.
Đoạn mã giả cho bộ mã hóa Encoder compressor và bộ giải mã Decoder Decompressor được mô tả như sau:
void Encoder() {
ExitLoop = true;
//StateStruct is a pair of int(ElementIndex, Statelndex) //Elementlndex represents the automaton //Statelndex is the state in the above automaton
StateStruct CurrState(0, 0); while(ExitLoop == false) {
Type = GetNextType(FilePointer, Elementlndex); switch(Type)
case OPENTAG:
//Encode ElementIndex in CurrState context EncodeOpenTag(CurrState, Elementlndex); Stack.push(CurrState);
CurrState = StateStruct(ElementIndex, 0); break;
case CLOSETAG:
//Encode CLOSETAG in CurrState context EncodeCloseTag(CurrState) if(Stack.empty() == true) { ExitLoop = true; } else { CurrState = Stack.pop();
//Make state transition in CurrState.Elementlndex //automaton and get the next state
CurrState.Statelndex =
MakeStateTransition(CurrState,Elementlndex); }
break; case PCDATA:
//Encode Pcdata in Currstate context EncodePcdata(CurrState); CurrState.Statelndex = MakeStateTransition(CurrState, PCDATA); break; } } } void Decoder() { ExitLoop = true; StateStruct CurrState(0, 0); while(ExitLoop == false) {
//Decode the type in CurrState context
Type = DecodeNextType(FilePointer, CurrState, Elementlndex);
switch(Type) {
//Write open tag of the Element of Elementlndex WriteOpenTag(Elementlndex); Stack.push(CurrState); CurrState = StateStruct(ElementIndex, 0); break; case CLOSETAG:
//Write close tag of the Element of ElementIndex WriteCloseTag(Elementlndex); if(Stack.empty() == true) { ExitLoop = true; } else { CurrState = Stack.pop(); CurrState.Statelndex = MakeStateTransition(CurrState,Elementlndex); } break; case PCDATA: DecodePcdata(CurrState); CurrState.Statelndex = MakeStateTransition(CurrState, PCDATA); break; } } } 3.4. XSAQCT 3.4.1. Tổng quan về XSAQCT
XSAQCT được phát âm là exact là một bộ nén XML phi cú pháp free-grammar)