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) có khả năng truy vấn. XSAQCT mượn kỹ thuật của các bộ nén khác để bóc tách cấu trúc tài liệu từ các giá trị dữ liệu. Điểm mới của XSAQCT là bộ nén này mã hóa thông tin tài liệu ngắn gọn và súc tích hơn so với các thông tin đầu vào. Sau đó nó sử dụng các bộ nén dữ liệu nền back-end phù hợp để nén bộ chứa lưu trữ cấu trúc tài liệu và bộ chứa lưu trữ giá trị dữ liệu. Phương pháp tiếp cận của XSAQCT là sử dụng các bộ chứa đủ lớn để có thể đạt được tỉ lệ nén hiệu quả, đồng thời cấu trúc của bộ chứa cũng không yêu cầu phải đ i hỏi giải nén toàn bộ tài liệu XML nén khi thực hiện một truy vấn. XSAQCT cũng được thiết kế để hỗ trợ giải nén lazy decompression tức là giải nén tài liệu ít nhất có thể khi thực hiện truy vấn.
XSAQCT được mô tả như là một ứng dụng cơ sở dữ liệu mà tập trung vào quá trình nén có khả năng truy vấn với sự truy cập ngẫu nhiên và tốc độ thực thi của quá trình giải nén. Bên cạnh đó, XSAQCT c n là một bộ nén tương tác interactive compressor mà có thể thực hiện bất kỳ loại truy vấn nào. Nó hỗ trợ cả quá trình nén không mất mát lossless
compression) lẫn hỗ trợ cho phép loại bỏ các khoảng trắng thừa. XSAQCT cũng áp dụng đánh chỉ mục và sử dụng bộ nhớ đệm để cải thiện tốc độ xử lý.
3.4.2. Kiến trúc của XSAQCT
Kiến trúc của XSAQCT được minh họa bởi hình 3.5 trong đó các hình chữ nhật được đánh bóng mờ biểu diễn các giai đoạn trung gian của quá trình nén.
Cho một tài liệu D, XSAQCT sử dụng SAX duy nhất quét, phân tích và mã hóa tài liệu D để tạo ra một cây chú thích annotated tree TA,D . Cũng tại thời điểm đó, các giá trị dữ liệu được đưa vào những bộ chứa thích hợp. Bước tiếp theo, TA,D được nén bao gồm hai bước. Bước thứ nhất ghi các chú thích của nó vào trong một bộ chứa. Bước thứ hai cây khung (skeleton tree) (TD không c n có chú thích được đưa vào một bộ chứa khác.
Cuối cùng, tất cả các bộ chứa c n lại được nén bằng cách sử dụng các bộ nén nền (back-end được xác định bởi người sử dụng và được ghi lại tạo đầu ra CD.
Chú ý rằng TA,D biểu diễn chính xác cấu trúc nhưng cô đọng súc tích hơn cấu trúc của tài liệu đầu vào D. TA,D giữ lại tất cả thông tin về thứ tự của các phần tử, thuộc tính.
XSAQCT sử dụng một container duy nhất cho quá trình lưu trữ các giá trị text của tất cả đường dẫn tương đương nhau ví dụ, các đường dẫn /a/b/t1, a/b/t2 và a/c/t1 với t1, t2 là các chuỗi text thì ta sẽ có /a/b/t1 tương đương /a/b/t2, trong khi đó a/b/t1 không tương đương với a/c/t1 .
Mỗi bộ chứa có thể được nén bằng cách sử dụng các bộ nén nền back-end) khác nhau phụ thuộc vào loại giá trị trong bộ chứa container. Các bộ nén nền back-end được sử dụng trong XSAQCT bao gồm: gzip, bzip2…, người dùng có thể bổ sung thêm nhiều bộ nén khác.
Quá trình giải nén bao gồm các bước sau:
1. Sử dụng bộ giải nén nền back-end decompressor để khôi phục lại nội dung của tất cả bộ chứa.
2. Chú thích lại re-annotation : sử dụng các chú thích và cây khung TD để tạo lại TA,D. 3. Khôi phục lại restoring : sử dụng TA,D để khôi phục lại tập tin được nén.
Ví dụ 3.18: Xem xét tài liệu D được minh họa trong hình 3.6. Ta thấy rằng, cây tài liệu không có bất kỳ các giá trị dữ liệu nào. Có 3 đường dẫn tương đương /b/c và hai đường dẫn tương đương a/b/e. Cây chú thích TA,D biểu diễn tài liệu D được minh họa trong hình 3.7. Các đường dẫn tương đương nhau đã được merge lại nên trong ví dụ này chỉ có một đường dẫn a/b/c và một đường dẫn a/b/e. Để hỗ trợ quá trình giải nén, chú thích được thêm vào các node của cây TA,D. Chú thích được kết hợp với node n sẽ là tổng số lượng con của m được gán nhãn bởi n, trong đó m là cha của node n. Trong ví dụ 3.18, node b trong cây TA,D được chú thích [3] bởi vì có 3 con được gán nhãn bởi “b” là con của node “a‟ trong cây tài liệu D. Node “e” được gán nhãn [0,0,2] bởi vì trong tài liệu D, không có con nào được gán nhãn “e‟ cho hai lần xuất hiện đầu tiên của node “b”, và có 2 con được gán nhãn “e” cho lần xuất hiện thứ 3 của node “b”.
Hình 3.6: Minh họa một tài liệu D đơn giản [20]
3.4.3. Quá trình xử lý thuộc tính và nội dung tài liệu được trộn
Thuộc tính được xử lý giống như phần tử và các chú thích của chúng được ghi vào cây chú thích TA,D. Hình 3.8 minh họa một tài liệu đơn giản với nội dung được trộn lẫn giữa các phần tử, thuộc tính và node văn bản. Cây chú thích TA,D và các bộ chứa văn bản được minh họa trong hình 3.9. Các node được đánh dấu “*” nếu phần tử tương ứng có nội dung được trộn và trong trường hợp này một văn bản rỗng được minh họa bởi hình hộp chứa “0” được thêm vào các bộ chứa văn bản khi cần thiết.
Trong bộ nén XASQCT, các giá trị dữ liệu của những đường dẫn tương đương nhau thì được lưu trữ vào một bộ chứa container riêng. Xét ví dụ trong hình 3.9 ta có t1 và t2 cùng đường dẫn /a được lưu trữ trong một bộ chứa; t3 được lưu trữ riêng trong một bộ chứa; t4, t5, t6 và t7 cùng đường dẫn /a/b được lưu trữ trong cùng một bộ chứa; t11 và t12 cùng đường dẫn /a/b/e được lưu trữ trong cùng một bộ chứa; t8, t9, t13 cùng đường dẫn /a/b/c được lưu trữ trong cùng một bộ chứa; t10 được lưu trữ trong một bộ chứa riêng; chú thích được gán cho “a” là [1]; chú thích được gán cho “b” là [3]; chú thích được gán cho “e” là [0,0,2]; chú thích được gán cho “c” là [1,1,1]; chú thích được gán cho “d” là [0,1,0].
Hình 3.8: Quá trình xử lý nội dung tài liệu được trộn [20]
3.4.4. Quá trình cài đặt XSAQCT
3.4.4.1. Quá trình xây dựng cây chú thích TA,D 3.4.4.1.1. Đặc điểm của cây chú thích TA,D 3.4.4.1.1. Đặc điểm của cây chú thích TA,D
Cây chú thích TA,D của tài liệu có độ cao bằng độ cao của tài liệu D, nhưng độ rộng lại hẹp hơn độ rộng của D. Chú thích của node A trong cây TA,D được ký hiệu là ann(A)=[a1,…,ak] và |ann A | là số lượng những số nguyên trong ann A , {A} là tổng của a1,…,ak. Xem xét các thuộc tính sau đây:
1. Trong D có a1,…,ak sự xuất hiện của A. 2. Nếu A có con B1,…,Bm trong TA,D thì:
2.1. ann(Bj) = [bj,1,…,bj,{A}]
Số lượng những số nguyên trong chú thích của từng node con bằng tổng số của những số nguyên trong node cha.
2.2.Trong D, node Aj có:
bj,1 các con được gán nhãn bởi B1. …
bj,{A} các con được gán nhãn bởi B{A}.
Trong ví dụ 3.18, node “b” trong TA,D có ann b =[3] và theo 1 có 3 sự xuất hiện của node “b” trong D, theo thuộc tính 2.1 trong phần 3.4.4.1.1, chú thích của các node con “e”, “c”, “d” của node “b” có 3 số nguyên: node “e” là 0,0,2; node “c” là 1,1,1; node “d” là 0,1,0. Để xem ví dụ của trường hợp thuộc tính 2.2 trong phần 3.4.4.1.1, xem chi tiết trong hình 3.15. Node “$” là con của node “a” có hai con là node “s” và “z”. Node “s‟ được chú thích là [1,2,0,1,0] và node “z” được chú thích là [0,1,1,0,0], nhưng trong hình 3.16, ta thấy có năm sự xuất hiện của “$” trong D.
- Lần xuất hiện đầu tiên của “$” có một con được gán nhãn bởi “s” và không có con nào được gán nhãn bởi “z”.
- Lần xuất hiện thứ hai của “$” có hai con được gán nhãn bởi “s” và một con được gán nhãn bởi “z”.
- Lần xuất hiện thứ ba của “$” không có con nào được gán nhãn bởi “s” và có một con được gán nhãn bởi “z”.
- Lần xuất hiện thứ tư của “$” có một con được gán nhãn bởi “s” và không có con nào được gán nhãn bởi “z”.
- Lần xuất hiện thứ năm của “$” không có con nào cả.
3.4.4.1.2. Cài đặt cây chú thích TA,D Khái niệm chu trình Khái niệm chu trình
Một tài liệu D có một chu trình nếu tồn tại một node n trong D mà có hai con x và y của n thỏa mãn điều kiện x<y và y<x trong đó, “<” biểu thị thứ tự xuất hiện . Nếu có chu trình thì phải thêm tên thẻ giả dummy tag ký hiệu “$” vào trong cây chú thích TA,D để
tránh các chu trình. Khi thực hiện quá trình giải nén, các node giả này sẽ được loại bỏ bởi bộ giải nén để tái tạo lại tài liệu gốc ban đầu.
Các chu trình có thể xảy ra trong hai trường hợp sau:
1. Node NA xuất hiện node NB và sau đó NA xuất hiện sau NB, trong đó NA và NB có cùng node cha. Ví dụ 3.19 sau đây minh họa trường hợp này.
Ví dụ 3.19: Minh họa tài liệu D có chu trình xảy ra. <parent>
<a></a> <b></b> <a></a> </parent>
2. NA xuất hiện trước NB và cả hai đều là con của Nparent1 Sau đó, NB xuất hiện trước NAvà cả hai đều là con của Nparent2, trong đó Nparent1 và Nparent2 có cùng đường dẫn ví dụ, chúng có cùng tổ tiên trong cây khung . Ví dụ 3.20 sau đây minh họa trường hợp này.
Ví dụ 3.20: Minh họa tài liệu D chứa một chu trình đơn giản như sau <super_parent> <parent> <a></a> <b></b> </parent> <parent> <b></b> <a></a> </parent> </super_parent>
Hình 3.11: Biểu diễn cây chú thích của tài liệu D có thêm các node giả “$” [20]
Hình 3.12: Khôi phục lại cây tài liệu D với các node giả “$” [20] Thuật toán 3.1
Đầu vào: Tài liệu XML D.
Đầu ra: Cây được chú thích TA,D.
Các ký hiệu sau đây được sử dụng trong quá trình xây dựng cây tài liệu được chú thích: 1. ann $ +=1 có nghĩa là nếu chú thích của $ kết thúc với “,” thì thêm “1,”; nếu
không thêm “,”.
2. ann x += 1 cho chú thích khác $ : nếu chú thích kết thúc với “,” thì thêm “0,”; nếu không thêm “,”.
3. Có một bảng T, mỗi d ng row có 3 đầu vào: một đường dẫn đầy đủ, một đồ thị được kết hợp với đường dẫn và một chú thích cho “$” đầu vào có thể rỗng . 4. “close absolute path p ”: mỗi node x trong đồ thị được kết hợp với đường dẫn p
thực hiện ann x +=1 và nếu đường dẫn p có một chú thích không rỗng cho “$” thì sau đó thực hiện ann $ +=1.
5. “cycle x ”: x đang là node hiện thời và thêm x vào đồ thị sẽ tạo ra một chu trình ví dụ nêú có đồ thị a ← b sau đó thêm vào node a thì sẽ ra một chu trình a ← b ← a .
Phương thức: Các phần tử được thêm vào trong cây được chú thích khi chúng được quét qua lần đầu tiên. Thuật toán sử dụng một SAX duy nhất cho tài liệu D và thực hiện các bước sau:
1. Đi lên từ node x đến y; nếu x là con cuối cùng ngoài cùng bên phải của y thì bước tiếp theo sẽ đi lên đến cha mẹ của y sau đó close x và loại bỏ thiết lập node hiện tại trong đồ thị.
2. Đi xuống node x:
- Thêm x vào đồ thị.
- Nếu một chu trình được tạo ra thì close x , sau đó thêm 1 vào ann x và tăng 1 cho chú thích của $ nếu chú thích không tồn tại hoặc kết thúc bằng “,”, sau đó tạo mới và khởi tạo giá trị của nó bắt đầu với 2 .
- Nếu không có chu trình tạo ra, sau đó thêm x vào trong đồ thị một node mới hoặc tăng chú thích của x đã tồn tại và thiết lập x là node hiện thời trong đồ thị.
3. Sau khi hoàn thành, kiểm tra các chú thích và thêm số “0” ở đầu cho các node chính và thêm “1” cho các node giả node $ .
Ví dụ 3.21: Xem xét cây tài liệu D được minh họa trong hình 3.13. Ta thấy, có sử dụng chỉ số cho các node ví dụ a1, a2, a3… là a; b1, b2, b3… là b; s1, s2, s3… là s; t1, t2, t3… là t; z1, z2 là z; x1, x2, x3 là x; y1, y2, y3 là y; u1, u2 là u.
Hình 3.13: Biểu diễn một tài liệu D sẽ được áp dụng thuật toán 3.1 [20]
Bảng 3.3 biểu diễn các bước thực hiện chính trong quá trình tạo mới một cây chú thích của tài liệu D trong hình 3.13. Mỗi bước mô tả quá trình xác định một node khi SAX quét qua, sau đó thay đổi đường dẫn path , đồ thị graph của nó và chú thích của $ nếu chú thích đã
tồn tại . Node hiện thời được in đậm. Ví dụ xem xét đường dẫn và đồ thị /r, a[1] chỉ ra rằng đồ thị có chứa một node a, node này được gán nhãn bởi 1 cho đường dẫn /r.
ảng 3.3: Mô tả các bước thực hiện thuật toán 3.1 khi tạo mới cây chú thích của tài