Mô tả Roaring bitmap

Một phần của tài liệu Khai thác k mẫu tuần tự phổ biến dựa trên roaring bitmap (Trang 58 - 66)

3.3 ROARING BITMAP

3.3.2 Mô tả Roaring bitmap

Cu trúc Roaring bitmap:

Hình3.8 Cấu trúc của Roaring bitmap

Phân vùng khoảng [0,n] của các chỉ mục 32 bit của bitmap thành các đoạn của 1 0 1 1 0 1 …………0 1 0 0 0 1 …………1 10 0... Bitmap dài nbit với các chỉ

mục 32 bit trong khoảng [0,n]

216 bit 216 bit

Số phần Số phần tử > 4096 tử <= 4096

Bitmap mảng

1 0 1 1 0 1 ……… {1, 5, ...}

{0, 1, …} Chỉ mục cấp 1 của Roaring bitmap (16 bit cao của các chỉ mục 32 bit)

các số nguyên có độ lớn tối ta là 216 chia sẻ cùng 16 bit quan trọng nhất (16 bit cao của mỗi chỉ mục 32 bit). Đoạn thứ nhất từ 0 đến 65535, đoạn thứ 2 từ 65536 đến 131071,… Sử dụng container chuyên dụng để lưu trữ 16 bit ít quan trọng nhất của chúng (16 bit thấp của mỗi chỉ mục).

Khi một đoạn không chứa hơn 4096 số nguyên, sử dụng một mảng được sắp xếp đểchứacác số nguyên16 bit được đóng gói. Khi có nhiều hơn 4096 số nguyên, sử dụng một bitmap 216bit. Như vậy, chúng tacó hai loại container: container mảng cho đoạn thưa thớt và container bitmap cho đoạn dày đặc. Ngưỡng 4096 đảm bảo rằng ở cấp độ củacontainer, mỗi số nguyên sử dụng không quá 16 bit (lớn hơn con số này thì một bitmap có hiệu quảsử dụng bộ nhớ tốt hơn mộtmảng.

Hình3.9 So sánh bộ nhớ được sử dụng cho mảng và bitmap (nguồn http://www.elasticsearch.org/blog/frame-of-reference-and-roaring-bitmaps/)

Các container được lưu trữ trong một mảng độngchia sẻ16 bit quan trong nhất: điều này đóng vai trị như là một chỉ mục cấp 1. Các mảng lưu trữ các container được sắp xếp theo 16 bitquan trọng nhất. Chỉmụccấp1 nàythườnglà nhỏ: khin =

1 000 000, nó chứa ít nhất 16 mục. Vì vậy nó thường được lưu lại trong bộ nhớ cache của CPU. Các container này không bao giờ nên sử dụng nhiều hơn 8 kB.

Mỗi container theo dõi số phần tử của nó (số nguyên) bằng cách sử dụng một bộ đếm. Như vậy việc tính tốn số phần từ của một Roaring bitmap có thể được thực hiện một cách nhanh chóng: nó sử dụng tối đa là n/216biến đếm. Nó cũng làm

cho truy vấn thứ hạng (rank query) và truy vấn chọn (select query) nhanh hơn so với một bitmap thông thường: các truy vấn thứ hạng đếm số lượng các bit 1 trong khoảng [0,i] trong khi các truy vấn chọn tìm kiếm vị trí của bit1 thứi.

Lỗi có thể xảy ra khi các container và mảng động sử dụng bộ nhớ vượt quá 16 bit/số nguyên. Tuy nhiên, miễn là số lượng container là nhỏ so với tổng số các số nguyên cần lưu trữ, chứchúng ta không bao giờ nên sử dụngsố nguyên lớn hơn16 bit. Giả định rằng số lượng container ít hơn rất nhiều so với tổng số nguyên. Chính xác hơn, chúng ta giả định rằng mật độ thường vượt quá 0,1% hoặc n/|S|> 0.001.

Khi cácứng dụng gặp phải bộ số nguyên với mật độ thấp (dưới 0,1%), một bitmap dường như không phải là cấu trúc dữ liệu thích hợp.

Truy cp Roaring bitmap:

Để kiểm tra sự hiện diện của một sốnguyên 32 bit x, đầu tiên chúng ta tìm kiếm

container tương ứng với x/216, sử dụng tìm kiếm nhị phân. Nếu một container bitmap được tìm thấy, chúng ta truy cập bit thứx mod 216. Nếu một container mảng đượctìm thấy, chúng ta tiếp tụctìm kiếm nhị phân một lần nữa.

Tương tự, khi chúng ta thêm hoặc loại bỏ một số nguyên x, đầu tiên chúng ta tìm container tương ứng. Nếu container được tìm thấy là bitmap, chúng ta thiết lập giá trị của bit tương ứng và cập nhật số phần tử của nó. Ngược lại,chúng ta sử dụng tìm kiếm nhị phân rồi thêm hoặc xóa tuyến tính (linear-time).

Khi loại bỏ một số ngun, một containerbitmap có thể trở thành một container mảng nếu số phần tử của nó chưa vượt quá 4096. Khi thêm một số nguyên, một container mảng có thể trở thành một container bitmap khi số phần tử của nó vượt quá 4096. Khi điều này xảy ra, một container mới được tạo ra chứa dữ liệu đươc cập nhật trong khi container cũ được bỏ đi. Chuyển đổi một container mảng thành một container bitmap được thực hiện bằng cách tạo một container bitmap mới với giá trị khởi tạo là các bit 0 rồi thiết lập các bit tương ứng. Để chuyển đổi một container bitmap thành một container mảng, chúng ta trích ra vị trí của các bit 1 sử dụng thuật toán 2.

Các phép toán logic:

Roaring bitmap cho phép thực hiện hai phép toán logic là phép hội (OR) và phép giao (AND). Một phép toán logic giữa hai Roaring bitmap bao gồm việc lặp và so sánh 16 bit cao (khóa) của các số nguyên trên các chỉ mục cấp 1. Để đạt hiệu quả tốt hơn, các mảng cấp 1 phải luôn được sắp xếp. Hai khóa được so sánh ở mỗi lần lặp. Nếu bằng nhau, mộtphép toán logic cấpthứ 2 giữa các container tương ứng được thực hiện. Điều này luôn luôn tạo ra một container mới. Nếu container không phải là rỗng, nó được thêm vào kết quả cùng với khóa. Sau đóbiến lặp lưu vị trí của mảng cấp 1 sẽ tăng lên một. Khi hai khóa khơng bằng nhau, mảng chứa container nhỏ nhất được tăng thêm một vị trí, và nếu một phép hội được thực hiện, khóa nhỏ nhất và một bản sao container tương ứng được thêm vào câu trả lời. Khi tính tốn các phép hội, chúng ta lặp lại cho đến khi đến cuối cảhai mảng cấp 1. Khi tính tốn các phép giao, chúng ta chấm dứt ngay sau khi một mảng được khai thác hết.

Hình3.10 Minh họa phép OR giữa hai Roaring bitmap khi chỉ mục cấp 1 không bằng nhau

Các mảng cấp 1 đãđược sắp xếp có chi phí cho các phép so sánh là O (n1+ n2), với n1 và n2 là chiều dài tương ứng của hai mảng. Chúng ta cũng duy trì các container mảng được sắp xếp để chúng có các ưu điểm tương tự nhau. Một container có thể được biểu diễn bởi hai cấu trúc dữ liệu khác nhau là: bitmap và mảng, mộtphép hộihoặc giaogiữa hai containergồmmột trong ba kịch bản sau:

Bitmap với Bitmap: Chúng ta lặp trên 1024 từ 64 bit. Với phép hội, chúng ta

OR {0, 3, ...} Roaring bitmap 1 {1, 2, ...} Roaring bitmap 2 1 0 1 1 1 0… 0 1 0 0 0 1… {1, 10, 25, …} {0, 15, 28, …} {0, 1, 2, 3, ...} 1 0 1 1 1 0… 0 1 0 0 0 1… {1, 10, 25, …} {0, 15, 28, …}

thực thi 1024 phép OR và ghi kết quả vào container bitmap mới (thuật toán 1). Số phần tử mới được tính tốn một cách hiệu quả trong Java bằng phương thức

Long.bitCount.

Hình3.11 Thuật tốn 1 - Thủ tục tính phép giao giữa hai container bitmap

Việc tính tốn các phép hội và tính số phần tử của kết quả là khá chậm so với việc tính tốn các phép hội đơn thuần. Tuy nhiên, có bốn yếu tố để giảm nhẹ vấn đề tiềm tàng này là:

 Các bộ xử lý thông dụng (Intel, AMD, ARM) có các chỉ thị để tính tốn nhanh số bit 1 trong một từ. Chỉ thị popcnt của Intel và AMD có một thơng

lượng cao như một phép tốn trên mỗi chu kỳ của CPU.

 Các bản Java gần đây đã dịch lời gọi tới phương thức Long.bitCount thành

các chỉ thị đếm bit nhanh.

 Các bộ xửlý thơng dụng có thể thực thi một vài phép toán cùng một lúc. Vì vậy,trong khi chúng ta nhận thành phầndữ liệu kế tiếp thì các phép giao của chúng được tính tốn và lưu vào bộ nhớ. Bộ xử lý có thể áp dụng chỉ thị

popcnt trên kết quả cuối cùng và tăng biến đếm phần tử phù hợp.

 Đối với các phép toán xử lý dữ liệu khơng tốn kém, bộ xử lý có thể khơng chạy hết cơng suất dodữ liệunhớtrong cache.

Để tính tốn các phép giao, đầu tiên chúng ta tính số phần tử của kết quả, sử dụng chỉ thị AND 1024 trên bit. Nếu số phần tử lớn hơn 4096, chúng ta xử lý nó như với phép giao, ghi kết quả của các phép toán AND vào một container bitmap

1. input: 2 bitmap A,Bđược lập chỉmục như là2 mảng chứa 1024 sốnguyên 64 bit

2. output: bitmap C là kết quảcủa phép giao giữa A với B và sốphần tửc của nó

3. c0

4. Lập chỉmục cho Cnhư là một mảng chứa 1024 sốnguyên 64 bit

5. for i{1, 2, …, 1024}do

6. CiAi OR Bi

7. cc + bitCount(Ci)

mới. Ngược lại, chúng ta tạo một container mảng mới và trích ra vị trí các bit 1 từ các phép tốn AND, sử dụng thuật tốn 2 (xem thuật tốn 3).

Hình3.12 Thuật toán 2 - Thuật tốn được tối ưu để chuyển đổi vị trí các bit 1 trong một bitmap thành một danh sách các số ngun.

Hình3.13 Thuật tốn 3 –Thủ tục tính tốn phép giao của hai container bitmapBitmap với Array: Khi một trong hai container là một bitmap và cái kia là một Bitmap với Array: Khi một trong hai container là một bitmap và cái kia là một

1. input:2 bitmap A,Bđược lập chỉmục như là 2 mảng chứa 1024 sốnguyên 64 bit

2. output: bitmap C là kết quả của phép giao giữa A với B, và sốphần tử c của nó

nếu c > 4096,ngược lại C là một mảng các sốnguyên

3. bitCount: trảvềtrọng lượng Hamming của sốnguyên 4. c 0

5. for i{1, 2, …,1024} do

6. cc + bitCount(Ai AND Bi)

7. if c > 4096 then

8. Lập chỉmục cho Cnhư là một mảng chứa 1024 sốnguyên 64 bit 9. for i{1, 2, …,1024} do

10. CiAi AND Bi

11. return C và c

12. else

13. Đặt D là một mảng các số nguyên được khởi tạo rỗng

14. for i{1, 2, …,1024} do

15. Thêm vịtrí các bit 1 trong AiAND Bivào D sửdụng thuật toán 2 16. return D

1. input: một sốnguyên w

2. output: một mảng S chứa các chỉmục

3. bitCount: trảvềtrọng lượng Hamming của sốnguyên 4. Đặt S là một danh sách được khởi tạo rỗng

5. while w0 do

6. tw ANDw

7. Thêm bitCount(t1) vào S

8. w w AND (w 1)

mảng động được sắp xếp thì phép giao có thể được tính tốn rất nhanh: chúng ta lặp qua mảng động được sắp xếp này và kiểm tra sự tồn tại của từng số nguyên 16 bit trong container bitmap. Kết quả được ghi vào một container mảng. Các phép hội cũng rất hiệu quả: chúng ta tạo một bản sao của bitmap và lặp qua toàn bộ mảng và thiết lập các bit tương ứng.

Array với Array: Đối với phép hội, nếu tổng các số phần tử của 2 mảng là không quá 4096, chúng ta sử dụng một thuật toán hợp nhất hai mảng. Ngược lại, chúng ta thiết lập các bit tương ứngcủa cả hai mảng vào một container bitmap. Sau đó, chúng ta tính tốn số phần tử sử dụng chỉ thị đếm bit nhanh. Nếusố phần tử là không quá 4096, chúng ta chuyển container bitmap thành container mảng (thuật toán 2). Đối với các phép giao, chúng ta sử dụng một sự hợp nhất đơn giản (giống như những gì được thực hiện trong merge sort) khi hai mảng có số phần tử có sự khác biệt bởi ít hơn một thừa sốcủa 64. Ngược lại, chúng ta sử dụngcác phép giao galloping. Kết quả là ln lnđượcghi vào một containermảngmới. Galloping là hồn hảo cho một sự hợp nhất đơn giản khi một mảng r là nhỏ hơn nhiều so với

mảngf còn lại bởi vì nó có thể bỏ qua nhiều phép so sánh.Bắt đầu từ đầu của cả hai mảng, chúng ta chọn các số nguyên có sẵn tiếp theo ritừ mảng r nhỏ và tìm một số

ngun có độ lớn tối thiểu fj trong mảng f lớn, đầu tiên tìm kiếm giá trị tiếp theo,

sau đó tìm một giá trị xa gấp đơi, và cứ tiếp tục như vậy. Sau đó, chúng ta sử dụng tìm kiếm nhị phân trong danh sách thứ hai với giá trị đầu lớn hơn hoặc bằngri.

Chúng ta cũng có thể thực hiệnmột sốphép tốn tại chỗ(in place) bởi vì chúng có thể nhanh hơn do tránh được việc cấp phát và khởi tạo các vùng nhớ mới.

 Khi tính tốn phép hội giữa hai container bitmap, chúng ta có thể thay đổi một trong hai container bitmap này thay vì tạo ra một container bitmap mới. Với phép giao thì cũng tương tự, chúng ta có thể thay đổi một trong hai container bitmap nếu số phần tử của kết quả vượt quá 4096.

 Khi tính tốn phép hội giữa một container mảng và một container bitmap, chúng ta có thể ghi kết quả vào container bitmap bằng cách lặp qua các giá trị của container mảng và thiết lập các bit tương ứng trong container bitmap.

Chúng ta có thể cập nhật số phần tử mỗi lần bằng cách kiểm tra giá trị của từ có bị thay đổi hay khơng.

Khi kết hợp nhiều bitmap, chúng ta sử dụng phương pháp tối ưu hóa khác. Ví dụ, khi tính tốn phép hội của nhiều bitmap (ví dụ, hàng trăm), chúng ta đầu tiên xác định vị trí tất cả các container có cùng khóa (sử dụng một hàng đợi ưu tiên). Nếu một container như vậy là một container bitmap, chúng ta có thể sao chép container bitmap này (nếu cần thiết) và tính tốn phép hộicủa các container này với tất cả các container tương ứng tại chỗ. Trong trường hợp này, việc tính tốn số phần tửcó thể được thực hiện một lần vào cuối(thuật tốn 4).

Hình3.14 Thuật tốn 4 –Thuật tốn được tối ưu để tính tốn phép hội của nhiều Roaring bitmap

1. input: một tập R của các Roaring bitmap được xem như là một tập các

container; mỗi container có sốphần tửvà một khóa 16 bit 2. output: một Roaring bitmap mới T là kết quảcủa phép hội 3. Đặt T là Roaringbitmap được khởi tạo rỗng.

4. Đặt P là min-heap của các container trong các bitmap của R, được cấu hình để

sắp xếp các container theo các khóa 16 bit của chúng. 5. while P do

6. Đặt x là phần tử gốc của P. Loại bỏ khỏi min-heap P tất cả các phần tử có cùng khóa nhưx, và gọi kết quảQ.

7. Sắp xếp Q giảm dần theo sốphần tử; Q1có sốphần tửlớn nhất.

8. Sao chép Q1 và gọi kết quả A. container A có thể là một container mảng hoặc một container bitmap.

9. for i{2, …, |Q|}do

10. if A là một container bitmap then

11. Tính tốn tại chỗ phép hội của A với Qi: AA OR Qi. Khơng tính lại số phần tửcủa A: chỉtính tốn các phép hội trên bit.

12. else

13. Tính phép hội của container mảng A với container mảng Qi: AA OR Qi. Nếu A có sốphần tử vướt q 4096 thì nó trởthành một container bitmap. 14. Nếu A là một container bitmap, cập nhật A bằng cách tính sốphần tửcủa nó. 15. Thêm A vào Roaring bitmap T.

Một phần của tài liệu Khai thác k mẫu tuần tự phổ biến dựa trên roaring bitmap (Trang 58 - 66)

Tải bản đầy đủ (PDF)

(76 trang)