Câu trả lời cơ bản nhất
Tôi đang sử dụng sql đơn giản bên dưới để mọi thứ rõ ràng và dễ đọc nhất có thể. Trong dự án của mình, bạn có thể sử dụng các phương pháp tiện lợi của Android. Đối db
tượng được sử dụng bên dưới là một phiên bản của SQLiteDatabase .
Tạo bảng FTS
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Điều này có thể đi trong onCreate()
phương thức của SQLiteOpenHelper
lớp mở rộng của bạn .
Điền bảng FTS
db.execSQL("INSERT INTO fts_table VALUES ('3', 'apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO fts_table VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO fts_table VALUES ('13', 'book', 'This is an example.')");
Sẽ tốt hơn nếu sử dụng SQLiteDatabase # insert hoặc các câu lệnh chuẩn bị hơn execSQL
.
Bảng FTS truy vấn
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Bạn cũng có thể sử dụng phương pháp truy vấn SQLiteDatabase # . Lưu ý MATCH
từ khóa.
Câu trả lời đầy đủ hơn
Bảng FTS ảo ở trên có vấn đề với nó. Mọi cột đều được lập chỉ mục, nhưng điều này sẽ lãng phí không gian và tài nguyên nếu một số cột không cần được lập chỉ mục. Cột duy nhất cần chỉ số FTS có lẽ là text_column
.
Để giải quyết vấn đề này, chúng tôi sẽ sử dụng sự kết hợp của một bảng thông thường và một bảng FTS ảo. Bảng FTS sẽ chứa chỉ mục nhưng không chứa dữ liệu thực tế từ bảng thông thường. Thay vào đó nó sẽ có một liên kết đến nội dung của bảng thông thường. Đây được gọi là bảng nội dung bên ngoài .
Tạo bảng
db.execSQL("CREATE TABLE example_table (_id INTEGER PRIMARY KEY, col_1 INTEGER, col_2 TEXT, text_column TEXT)");
db.execSQL("CREATE VIRTUAL TABLE fts_example_table USING fts4 (content='example_table', text_column)");
Lưu ý rằng chúng ta phải sử dụng FTS4 để làm điều này chứ không phải FTS3. FTS4 không được hỗ trợ trong Android trước phiên bản API 11. Bạn có thể (1) chỉ cung cấp chức năng tìm kiếm cho API> = 11 hoặc (2) sử dụng bảng FTS3 (nhưng điều này có nghĩa là cơ sở dữ liệu sẽ lớn hơn vì tồn tại cột văn bản đầy đủ trong cả hai cơ sở dữ liệu).
Điền các bảng
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('3', 'apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('13', 'book', 'This is an example.')");
(Một lần nữa, có nhiều cách tốt hơn để thực hiện chèn hơn là với execSQL
. Tôi chỉ đang sử dụng nó để dễ đọc.)
Nếu bạn cố gắng thực hiện một truy vấn FTS ngay bây giờ, fts_example_table
bạn sẽ không nhận được kết quả. Lý do là thay đổi một bảng không tự động thay đổi bảng khác. Bạn phải cập nhật bảng FTS theo cách thủ công:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(Tương docid
tự như rowid
bảng thông thường.) Bạn phải đảm bảo cập nhật bảng FTS (để nó có thể cập nhật chỉ mục) mỗi khi bạn thực hiện thay đổi (CHÈN, XÓA, CẬP NHẬT) đối với bảng nội dung bên ngoài. Điều này có thể trở nên cồng kềnh. Nếu bạn chỉ đang tạo cơ sở dữ liệu được điều chỉnh trước, bạn có thể làm
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
sẽ xây dựng lại toàn bộ bảng. Tuy nhiên, điều này có thể chậm, vì vậy nó không phải là điều bạn muốn làm sau mỗi lần thay đổi nhỏ. Bạn sẽ làm điều đó sau khi hoàn thành tất cả các phần chèn trên bảng nội dung bên ngoài. Nếu bạn cần tự động đồng bộ hóa cơ sở dữ liệu, bạn có thể sử dụng trình kích hoạt . Tới đây và cuộn xuống một chút để tìm chỉ đường.
Truy vấn cơ sở dữ liệu
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Điều này giống như trước đây, ngoại trừ lần này bạn chỉ có quyền truy cập vào text_column
(và docid
). Điều gì sẽ xảy ra nếu bạn cần lấy dữ liệu từ các cột khác trong bảng nội dung bên ngoài? Vì docid
bảng FTS khớp với rowid
(và trong trường hợp này _id
) của bảng nội dung bên ngoài, bạn có thể sử dụng một phép nối. (Cảm ơn câu trả lời này đã giúp về điều đó.)
String sql = "SELECT * FROM example_table WHERE _id IN " +
"(SELECT docid FROM fts_example_table WHERE fts_example_table MATCH ?)";
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery(sql, selectionArgs);
Đọc thêm
Xem kỹ các tài liệu này để xem các cách sử dụng bảng ảo FTS khác:
Ghi chú bổ sung