Berikut adalah beberapa "aturan main" yang harus Anda ingat untuk memecahkan masalah ini. Anda mungkin sudah mengetahuinya, tetapi menyatakannya dengan jelas dapat membantu mengonfirmasi pembaca lain.
- Semua indeks di MySQL hanya dapat mereferensikan kolom dalam satu tabel dasar. Anda tidak dapat membuat indeks teks lengkap yang mengindeks di beberapa tabel.
- Anda tidak dapat menentukan indeks untuk tampilan, hanya tabel dasar.
- Sebuah
MATCH()
kueri terhadap indeks teks lengkap harus cocok dengan semua kolom dalam indeks teks lengkap, dalam urutan yang dinyatakan dalam indeks.
Saya akan membuat tabel ketiga untuk menyimpan konten yang ingin Anda indeks. Tidak perlu menyimpan konten ini secara berlebihan -- simpan hanya di tabel ketiga. Ini meminjam konsep "superclass umum" dari desain berorientasi objek (sejauh kita dapat menerapkannya pada desain RDBMS).
CREATE TABLE Searchable (
`id` SERIAL PRIMARY KEY,
`title` varchar(100) default NULL,
`description` text,
`keywords` text,
`url` varchar(255) default '',
FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shopitems` (
`id` INT UNSIGNED NOT NULL,
`ShopID` INT UNSIGNED NOT NULL,
`ImageID` INT UNSIGNED NOT NULL,
`pricing` varchar(45) NOT NULL,
`datetime_created` datetime NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shops` (
`id` INT UNSIGNED NOT NULL,
`owner_id` varchar(255) default NULL,
`datetime_created` datetime default NULL,
`created_by` varchar(255) default NULL,
`datetime_modified` datetime default NULL,
`modified_by` varchar(255) default NULL,
`overall_rating_avg` decimal(4,2) default '0.00',
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Perhatikan bahwa satu-satunya tabel dengan kunci kenaikan otomatis sekarang Searchable
. Tabel shops
dan shopitems
gunakan kunci dengan tipe data yang kompatibel, tetapi bukan penambahan otomatis. Jadi, Anda harus membuat baris di Searchable
untuk menghasilkan id
nilai, sebelum Anda dapat membuat baris yang sesuai di salah satu shops
atau shopitems
.
Saya telah menambahkan FOREIGN KEY
deklarasi untuk tujuan ilustrasi, meskipun MyISAM akan mengabaikan batasan ini secara diam-diam (dan Anda sudah tahu bahwa Anda harus menggunakan MyISAM untuk mendapatkan dukungan untuk pengindeksan teks lengkap).
Sekarang Anda dapat mencari konten tekstual dari kedua shops
dan shopitems
dalam satu kueri, menggunakan indeks teks lengkap tunggal:
SELECT S.*, sh.*, si.*,
MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;
Tentu saja, untuk baris tertentu di Searchable
hanya satu tabel yang cocok, baik toko atau barang toko, dan tabel ini memiliki kolom yang berbeda. Jadi sh.*
atau si.*
akan NULL dalam hasilnya. Terserah Anda untuk memformat output di aplikasi Anda.
Beberapa jawaban lain menyarankan menggunakan Sphinx Search . Ini adalah teknologi lain yang melengkapi MySQL dan menambahkan kemampuan pencarian teks lengkap yang lebih canggih. Ini memiliki kinerja yang luar biasa untuk kueri, sehingga beberapa orang menjadi sangat terpesona dengannya.
Tetapi membuat indeks dan terutama menambah indeks secara bertahap itu mahal. Faktanya, memperbarui indeks Pencarian Sphinx sangat mahal sehingga solusi yang disarankan adalah membuat satu indeks untuk data lama yang diarsipkan, dan indeks lain yang lebih kecil untuk data terbaru yang kemungkinan besar akan diperbarui. Kemudian setiap pencarian harus menjalankan dua kueri, terhadap dua indeks terpisah. Dan jika data Anda tidak sesuai dengan pola data lama yang tidak berubah, maka Anda mungkin tidak dapat memanfaatkan trik ini.
Kembali komentar Anda:Berikut kutipan dari dokumentasi Pencarian Sphinx tentang pembaruan langsung ke indeks:
Idenya adalah karena memperbarui indeks Pencarian Sphinx mahal, solusi mereka adalah membuat indeks yang Anda perbarui sekecil mungkin. Sehingga hanya posting forum terbaru (dalam contoh mereka), sedangkan riwayat yang lebih besar dari posting forum yang diarsipkan tidak pernah berubah, jadi Anda membuat indeks kedua yang lebih besar untuk koleksi itu sekali. Tentu saja jika Anda ingin melakukan pencarian, Anda harus menanyakan kedua indeks tersebut.
Secara berkala, katakanlah seminggu sekali, pesan forum "terbaru" akan dianggap "diarsipkan" dan Anda harus menggabungkan indeks saat ini untuk posting terbaru ke indeks yang diarsipkan, dan memulai indeks yang lebih kecil dari awal. Mereka menegaskan bahwa menggabungkan dua indeks Pencarian Sphinx lebih efisien daripada mengindeks ulang setelah pembaruan data.
Tetapi maksud saya adalah bahwa tidak setiap kumpulan data secara alami termasuk dalam pola memiliki kumpulan data yang diarsipkan yang tidak pernah berubah, versus data terbaru yang sering diperbarui.
Ambil database Anda misalnya:Anda memiliki toko dan item toko. Bagaimana Anda bisa memisahkan ini menjadi baris yang tidak pernah berubah, versus baris baru? Setiap toko atau produk dalam katalog harus diizinkan untuk memperbarui deskripsinya. Tapi karena itu akan membutuhkan membangun kembali seluruh indeks Pencarian Sphinx setiap kali Anda membuat perubahan, itu menjadi operasi yang sangat mahal. Mungkin Anda akan mengantri perubahan dan menerapkannya dalam batch, membangun kembali indeks seminggu sekali. Tapi coba jelaskan kepada penjual toko mengapa perubahan kecil pada deskripsi toko mereka tidak akan berlaku sampai Minggu malam.