Giả sử lựa chọn s1=1, s2=2, s3=4.
<12; 38, 17, 13, 34, 6, 4, 1, 3, 1, 2, 3, 1> Từ bảng trước ta có:
Mỗi bộ chọn lọc có 4bits (2bits cho w, 2bits để chọn s1-s3. Vì vậy cần 16bits cho 4 cặp w-s)
Vậy cần 16+ (6×4+3×1+2×4+2×3)=57bits để mã hóa cho danh sách này.
Ví dụ 2: [17] Xét cấu trúc khoảng cách d sau:
<14; 4, 6, 1, 1, 3, 5, 1, 7, 1, 13, 20, 1, 12, 20> phân đoạn các khoảng cách thành các cụm bits như sau:
<14; (3,9: 4, 6, 1, 1, 3,5,1,7), (4, 2: 6), (1,1:1), (4, 2: 12, 20)>
Mỗi bộ chọn lọc có 4bits (2bits cho w, 2bits để chọn s1-s3. Vì vậy cần 16bits cho 4 cặp w-s)
Vậy cần 16+(3×9+4×2+1×1+4×2)=60 bits để mã hóa
=> so với tổng dung lượng trong phương pháp nén S9 thì việc nén đã làm giảm được không gian lưu trữ từ 64bits xuống 60bits
Đánh giá phương pháp: Như vậy so với tổng dung lượng thì việc nén đã làm giảm
2.3.4 PforDelta
Ý tưởng:[11] Nén hoặc giải nén nhiều giá trị trong cùng một block.
PFD chia danh sách chỉ số ngược vào trong các khối (blocks), thường mỗi khối khoảng 128 khoảng cách. Để mã hóa các khoảng cách d vào trong các khối nó sẽ loại bỏ khoảng 10% các khoảng cách d lớn nhất vào trong một khối và lưu trữ chúng vào không gian bộ nhớ riêng biệt. Đây là những trường hợp ngoại lệ (Exception array) của khối. Còn lại chúng ta sẽ lưu trữ chúng vào trong một khối, thường mỗi khối như vậy lưu trữ các khoảng cách d khác nhau là bội số của 32 .
Đầu tiên PFD sẽ xác định b bit cho hầu hết các giá trị nhỏ hơn 2b được mã hóa. Các giá trị còn lại gọi là trường hợp ngoại lệ được mã hóa một cách riêng biệt. Mặc dù các trường hợp ngoại lệ được lưu trữ trong một không gian riêng biệt nhưng vẫn duy
trì các slots cho chúng ở các vị trí tương ứng. Điều này tạo điều kiện cho quá trình giải mã. Đối với mỗi khối (block) duy trì một header để chỉ thông tin nén được sử dụng
trong khối.
Để lấy lại vị trí của các trường hợp ngoại lệ, trong header sẽ lưu trữ các ngoại lệ đầu tiên. Trong slot (khe) của mỗi ngoại lệ sẽ lưu trữ thông tin cho các ngoại lệ tiếp theo trong block. Điều này tạo một danh sách liên kết giữa các slot. Trong trường hợp
đó giá trị b là quá nhỏ và không thể chứa các thông tin của các ngoại lệ tiếp theo. Thuật toán sẽ bổ sung thêm trường hợp ngoại lệ giữa hai trường hợp ngoại lệ ban đầu. Điều này sẽ làm tăng không gian lưu trữ khi danh sách chứa quá nhiều số nhỏ.
Để giải mã cho một block, đầu tiên lấy b từ header và gọi các hàm chức năng
có được cho các khoảng cách d từ b bits. Mỗi b như vậy có một chức năng riêng để có
thể mã hóa hiệu quả. Mỗi khi giải mã các Dgaps duyệt qua các danh sách trường hợp
ngoại lệ của các khối
Ví dụ: Cần nén 128 số nguyên liên tiếp vào một dãy.
Để làm điều này, đầu tiên xác định giá trị b nhỏ nhất cho đa số trong 128 giá trị mà có giá trị nhỏ hơn 2b. Giả sử 90% là có giá trị nhỏ hơn 32=25. Vậy chọn b=5
Phân bổ 128 giá trị ×5bits slots, cộng thêm không gian cho các trường hợp ngoại lệ. Trường hợp ngoại lệ sẽ được lưu trữ ở cuối (mỗi trường hợp sử dụng 4 bytes) Cụ thể: b=5 và trình tự 23, 41, 8, 12, 30, 68, 18, 45, 21, 9, ..
Trường hợp ngoại lệ (màu xám) từ danh sách liên kết với các vị trí (ví dụ: 3 có nghĩa là: “ngoại lệ tiếp theo trừ đi 3 giá trị trước nó”)
Một slot cho vị trí của ngoại lệ đầu tiên (hoặc lưu trữ trong một mảng riêng biệt)
Đánh giá phương pháp:
- Việc giải nén là đơn giản và rất nhanh chóng
Đầu tiên copy 128 số b bits vào một mảng số nguyên (rất nhanh cho mỗi phần tử).
Sau đó duyệt qua danh sách liên kết và vá các trường hợp ngoại lệ (chậm hơn cho mỗi phần tử nhưng chỉ áp dụng cho một số ít các trường hợp ngoại lệ).
Nếu trường hợp ngoại lệ <10% trong tổng số các khoảng cách thì sẽ rất nhanh chóng để giải nén.
Ở giai đoạn đầu tiên: vòng lặp cho hiệu suất tốt nhất – mã hóa cứng cho mỗi b. - Cải thiện việc nén danh sách chỉ số đơn giản hiệu quả: không sử dụng 32bits/trường hợp ngoại lệ.
Sử dụng tối đa trong số 128 số liên tiếp để lựa chọn số bit.
Nén tốt hơn 10-20% cùng với một tốc độ cơ bản (nếu được thực hiện đúng cách).
2.3.5 Interpolative Coding
Đây là kỹ thuật mã hóa đã được đề xuất ý tưởng trong [8, 11] cho các tập tài liệu xuất hiện theo cụm hoặc xuất hiện trong các tập tài liệu lớn.
Ý tưởng: Mã hóa đệ quy với các dãy số nguyên tăng dần. Giả sử xét dãy các docID d=d1,…,dn với di<di+1, i<n.
Tại mỗi lần lặp, dãy được mã hóa có chứa các tham số sau: - n: số phần tử trong dãy (số các khoảng cách docID)
- l, r: chỉ số trái và chỉ số phải nhằm để phân chia ranh giới dãy (ví dụ: dl, dl+1,….dr)
- Một giá trị ràng buộc thấp hơn low để chỉ giá trị thấp nhất trong dãy và một ràng buộc cao hi để chỉ giá trj cao nhất trog dãy, do đó ta có low≤dl và hi≥dr.
Ban đầu đặt l=1, r=n, low=d1 và hi=dn. Tại mỗi bước mã hóa phần tử ở giữa dm với m=⌊(l+r)/2⌋ và sau đó mã hóa đệ quy hai dãy dl,….,dm-1 và dm+1,….,dr bằng cách sử
dụng các tham số [l, r, low, hi] được tính toán lại. Để mã hóa các phần tử ở giữa sử dụng bốn giá trị [l, r, low, hi] sao cho mã hóa nó với số bit ít nhất có thể. Cụ thể ta
nhận thấy rằng chắc chắn dm≥low+m-l (trong phần đầu của dãy ta có m-l là giá trị khác biệt và low là giá trị nhỏ nhất và dm≤hi-(r-m). Vì vậy dm nằm trong khoảng [low+m-l,
hi-r+m] và có thể mã hóa phần tử ở giữa sử dụng ⌈log2x⌉ bit, với x=hi-low-r+l. Giả sử đang mã hóa dm-(low+m-l). Bằng cách này IPC có thể sử dụng ít bit cho mỗi giá trị
trong dãy hoặc là thậm chí không sử dụng bit nào với trường hợp dãy số tăng dần như
[i, i+1,…,i+n-1].
Mã hóa đệ quy được thực hiện như sau:
- Đối với dãy dl,…,dm-1, tham số low được tính tương tự các bước trước, từ dl
không có sự thay đổi nhưng hi=dm-1 do đó dm-1≤dm-1
- Đối với dãy dm+1,…,dr tham số hi tương tự như trước, từ dr không có sự thay
đổi nhưng low=dm+1, do dm+1≥dm+1
- Tham số l và r được sửa đổi cho phù hợp.
Ví dụ: Cho khoảng cách d như sau:
Trong ví dụ trên các ô bên trái và phải tương ứng với các chỉ số trái và phải của mỗi lần lặp trong dãy số. Chỉ số trái là chỉ số được mã hóa. Thủ tục thực hiện là preoder của cây nhị phân cân bằng. Chú ý khi gặp một dãy có dạng [low, low+1, …,low+n-1] nó không thực hiện. Do đó các số được mã hóa theo trình tự sau: 9 (3bit), 3(3bit), 5(1bit), 7(1bit), 18(6bit), 11(1bit), 15(4bit).
Đánh giá phương pháp [11]:
- Tỉ lệ nén được xác định thông qua dung lượng bộ nhớ chính cần thiết. Trong
phương pháp này tỉ lệ nén đạt 3/10 so với PFD trong khi đó nó cho phép giải nén nhanh trong suốt danh sách chỉ số đảo ngược.
- Tốc độ giải nén thường khoảng từ hàng trăm đến hàng triệu số nguyên trên mỗi giây, nó rất quan trọng thông qua câu truy vấn. Ngược lại tốc độ nén lại không quan trọng bằng bởi mỗi danh sách chỉ số đảo ngược nén chỉ một lần trong quá trình xây dựng chỉ số còn giải nén được thực hiện nhiều lần trong quá trình truy vấn.
2.4 Cải tiến thuật toán PFD
Một nhược điểm của việc nén cấu trúc chỉ số theo phương pháp PFD là khi hai trường hợp ngoại lệ liên tiếp có khoảng cách hơn 2b, lúc đó cần sử dụng nhiều hơn một offset để đại diện cho khoảng cách bằng cách buộc các trường hợp ngoại lệ bổ sung giữa hai trường hợp ngoại lệ này. Không thể giải quyết được vấn đề này bằng cách tăng b điều này sẽ làm lãng phí rất nhiều bit khoảng trên 90% giá trị, nhưng nếu giảm b thì sẽ xảy ra nhiều trường hợp ngoại lệ. Điều này có nghĩa là với thuật toán PFD không thể sử dụng giá trị của b nhỏ hơn 3. Nhưng trường hợp này lại quan trọng trong trường hợp sắp xếp lại tập tài liệu.
Trường hợp 1: Để khắc phục vấn đề trên thuật toán xây dựng một cấu trúc mã
mới lưu trữ các giá trị offset và các bộ phận của các trường hợp ngoại lệ trong hai
mảng bổ sung. Đặc biệt đối với một ngoại lệ sẽ lưu trữ b bit thấp hơn thay vì bù đắp
các ngoại lệ tiếp theo trong slot b bit của nó trong khi đó lưu trữ các bit tràn cao hơn và offset vào hai mảng riêng biệt. Hai mảng có thể được nén bằng bất kỳ phương pháp
nào, đặc biệt phương pháp nén S16 là đặc biệt thích hợp. Phương pháp cải tiến này gọi là NewPFD.
Ví dụ [11]: Dùng 2 bít để nén 128 số cho dãy các khoảng cách sau:
Trường hợp 2: Lựa chọn giá trị b cho mỗi block. Việc lựa chọn một ngưỡng
liên tục cho số trường hợp ngoại lệ không đảm bảo cân bằng tốt giữa kích thước được nén và tốc độ giải nén, b tốt nhất sẽ được thực hiện lựa chọn giữa kích thước được nén
và tốc độ giải nén. Gán b với kích thước nhỏ nhất cho mỗi block và sau đó tăng tốc độ
như mong muốn bằng cách chọn một khối để tiết kiệm thời gian nhất cho mỗi lần tăng kích thước và thay đổi giá trị b của khối đó. Phương pháp cải tiến này gọi là OptPFD. Ở đây đối với một tốc độ có thể dễ dàng đưa ra được các quy tắc đơn giản về sự lựa chọn b thay vì thực hiện tối ưu hóa lặp đi lặp lại. Như vậy thuật toán này có thể thực hiện rất hiệu quả ngay cả trên tập dữ liệu lớn.
Hình 2.6 - Sơ đồ mục tiêu cho OptPFD [11]
KẾT LUẬN CHƯƠNG 2
Trong chương này đã trình bày các phương pháp nén chỉ mục, nén chỉ mục ngược một cách khái quát trên máy tìm kiếm và đưa ra các đánh giá từ các thực nghiệm của các bài báo các phương pháp cơ bản và cập nhật. Luận văn phân tích thuật toán cũng như ưu điểm và nhược điểm của mỗi phương pháp. Từ những phân tích trên luận văn sẽ trình bày tổ chức chỉ mục ngược trong Lucene và ứng dụng Lucene trong cài đặt lập chỉ mục theo nội dung chương 3
Mục tiêu:
- Giải nén tốc độ trên 1200milion DocID/second
- Kích thước nén không nhiều hơn 1.5MB/query
CHƯƠNG III. TÌM HIỂU VỀ LUCENE
Một cách tiếp cận hiệu quả để giải quyết vấn đề phát triển hệ thống tìm kiếm là sử dụng các thư viện mã nguồn mở để xây dựng hệ thống tìm kiếm. Lucene là một trong các thư viện mã nguồn mở hỗ trợ các chức năng cần thiết của một hệ thống tìm kiếm thông tin. Chính vì vậy tôi đã đi sâu vào nghiên cứu Lucene trong [16] để ứng dụng vào cài đặt lập chỉ mục cho demo của mình.
3.1. Tìm hiểu về lucene
3.1.1. Giới thiệu chung về Lucene
Lucene cung cấp những API cơ bản cho phép thực hiện đánh chỉ mục trên toàn bộ nội dung văn bản và sau đó có thể tìm kiếm dựa trên các tập tin nghịch đảo (inverted index) mà Lucene tạo ra khi thực hiện lập chỉ mục. Lucene không quan tâm đến nguồn gốc của dữ liệu, định dạng của nó, hoặc thậm chí ngôn ngữ của nó miễn là có thể chuyển đổi nguồn dữ liệu sang văn bản. Điều này có nghĩa là có thể sử dụng Lucene để lập chỉ mục và tìm kiếm dữ liệu được lưu trữ trong các tập tin: các trang web trên máy chủ, tài liệu được lưu trữ trong hệ thống, các tập tin văn bản đơn giản, tài liệu Microsoft Word, HTML hoặc file PDF hoặc bất kỳ định dạng khác mà từ đó có thể truy xuất thông tin văn bản. Với Lucene có thể lập chỉ mục và tìm kiếm các tin nhắn mail, danh sách lưu trữ thư gửi, chats, trang Wiki…
Lucene bao gồm 3 thành phần cơ bản hỗ trợ cho quá trình lập chỉ mục và tìm kiếm.
- Indexing
- Search (Tìm kiếm) - Phân tích
3.1.2. Tìm hiểu các lớp đối tượng lập chỉ mục
Để thực hiện lập chỉ mục một cách đơn giản nhất đối tượng lập chỉ mục bao gồm các thành phần:
IndexWriter: là lớp đối tượng trung tâm của tiến trình lập chỉ mục. Lớp này sẽ
tạo ra tập chỉ mục mới và bổ sung thêm chỉ số cho tập tài liệu mới hoặc mở một tập chỉ mục có sẵn và không được phép đọc hay tìm kiếm trên tập chỉ mục đó. Đây là lớp dùng để thao tác chỉnh sửa chỉ mục.
Directory: là lớp đối tượng xác định vị trí của tập chỉ mục. Có thể lưu trữ một
chỉ số Lucene trên ổ đĩa. Để làm được như vậy cần sử dụng FSDirectory, lớp con
Dicrectory để duy trì danh sách các tập tin trong hệ thống như làm trong chỉ mục. Việc
giống như FSDirectory, RamDirectory nắm giữ tất cả dữ liệu của nó trong bộ nhớ.
Việc thực thi này rất hữu ích cho các chỉ số nhỏ hơn có thể được lưu trữ trong bộ nhớ và có thể bị hủy khi kết thúc một ứng dụng. Bởi vì dữ liệu lưu trữ trong bộ nhớ nhanh
còn trong ổ đĩa cứng chậm hơn vì vậy RamDirectory phù hợp cho trường hợp cần truy
cập nhanh các chỉ số trong cả trường hợp lập chỉ mục và tìm kiếm.
Analyzer: được sử dụng để phân tích văn bản trước khi được lập chỉ mục. Bộ
Analyzer quy định trong cấu trúc InderWriter, chịu trách nhiệm thực hiện giải nén ra
tokens của văn bản được lập chỉ mục và loại bỏ các phần còn lại. Nếu nội dung văn bản lập chỉ mục không đơn giản thì cần phải được chuyển đổi sang nó. Analyzer là thành phần quan trọng của Lucene và có thể được sử dụng nhiều hơn quy trình lọc đầu vào, nó là một thành quan trọng của thiết kế ứng dụng.
Document: là một lớp đối tượng biểu diễn tập hợp các trường, mỗi trường sẽ
chứa nội dung văn bản cần lập chỉ mục. Các siêu dữ liệu như tác giả, tiêu đề, chủ đề, ngày sửa đổi được lập chỉ mục và lưu trữ riêng biệt như các trường của tập tài liệu.
Field: trường thông tin của tài liệu. Mỗi Field sẽ có tên và giá trị phù hợp để
lưu trữ một trường thông tin nhất định. Lucene cung cấp bốn loại Field khác nhau để chọn:
Keyword: không phân tích như được lập chỉ mục và lưu trữ chỉ số đúng nguyên
văn từ khóa. Đây là loại thích hợp cho các lĩnh vực có giá trị ban đầu cần được bảo tồn toàn bộ chẳnng hạn như URL, file đường dẫn hệ thống tập tin, ngày tháng, tên người, số an sinh xã hội, số điện thoại...Ví dụ chúng ta sử dụng hệ thống đường dẫn tập tin
trong indexer gọi là trường Keyword.
UnIndexed: không phải phân tích cũng như không được lập chỉ mục nhưng giá
trị của nó được lưu trữ như trong các chỉ số. Đây là loại thích hợp cho các lĩnh vực mà cần hiển thị kết quả tìm kiếm (chẳng hạn như một URL hoặc cơ sở dữ liệu chính quan trọng) nhưng sẽ có giá trị mà không bao giờ tìm kiếm trực tiếp được. Kể từ khi giá trị ban đầu của một trường thuộc loại này được lưu trữ trong các chỉ số, loại này không thích hợp cho việc lưu trữ các lĩnh vực có giá trị rất lớn.
UnStored: ngược lại với UnIndexed. Loại Field này được phân tích và chỉ mục
nhưng không được lưu trữ trong tập chỉ mục. Nó thích hợp cho lập chỉ mục một số lượng lớn các văn bản mà không cần phải được lấy ở dạng ban đầu của nó chẳng hạn