Saya bertanya-tanya apa cara terbaik untuk menerapkan sistem tag, seperti yang digunakan pada SO. Saya sedang memikirkan hal ini, tetapi saya tidak dapat menemukan solusi skalabel yang baik.
Saya berpikir untuk memiliki solusi 3 tabel dasar: memiliki tags
meja, tabel, articles
dan tag_to_articles
meja.
Apakah ini solusi terbaik untuk masalah ini, atau adakah alternatifnya? Dengan menggunakan metode ini tabel akan menjadi sangat besar pada waktunya, dan untuk pencarian ini saya asumsikan tidak terlalu efisien. Di sisi lain, tidak penting bahwa kueri dijalankan dengan cepat.
Jawaban:
Saya yakin Anda akan menemukan posting blog yang menarik ini: Tag: skema database
Solusi "MySQLicious"
Dalam solusi ini, skema hanya memiliki satu tabel, itu dinormalisasi. Jenis ini disebut "solusi MySQLicious" karena MySQLicious mengimpor data del.icio.us ke dalam tabel dengan struktur ini.
Intersection (AND) Query untuk “search + webservice + semweb”:
Kueri Union (OR) untuk “search | webservice | semweb”:
Minus Query untuk "search + webservice-semweb"
Solusi "Scuttle"
Scuttle mengatur datanya dalam dua tabel. Tabel "scCategories" adalah "tag" -tabel dan memiliki kunci asing ke "bookmark" -tabel.
Intersection (AND) Query untuk "bookmark + webservice + semweb":
Pertama, semua kombinasi bookmark-tag dicari, di mana tag-nya adalah "bookmark", "webservice" atau "semweb" (c.category IN ('bookmark', 'webservice', 'semweb')), lalu hanya bookmark yang sudah mendapatkan ketiga tag yang dicari diperhitungkan (HAVING COUNT (b.bId) = 3).
Union (OR) Query untuk “bookmark | webservice | semweb”: Tinggalkan klausa HAVING dan Anda memiliki union:
Minus (Exclusion) Query untuk “bookmark + webservice-semweb”, yaitu: bookmark AND webservice AND NOT semweb.
Meninggalkan HAVING COUNT mengarah ke Query untuk “bookmark | webservice-semweb”.
Solusi "Toxi"
Toxi membuat struktur tiga meja. Melalui tabel "tagmap", bookmark dan tag terkait n-to-m. Setiap tag dapat digunakan bersama dengan bookmark yang berbeda dan sebaliknya. Skema DB ini juga digunakan oleh wordpress. Kueri cukup sama seperti pada solusi "scuttle".
Intersection (AND) Query untuk "bookmark + webservice + semweb"
Kueri Union (OR) untuk “bookmark | webservice | semweb”
Minus (Exclusion) Query untuk “bookmark + webservice-semweb”, yaitu: bookmark AND webservice AND NOT semweb.
Meninggalkan HAVING COUNT mengarah ke Query untuk “bookmark | webservice-semweb”.
sumber
Tidak ada yang salah dengan solusi tiga meja Anda.
Pilihan lainnya adalah membatasi jumlah tag yang dapat diterapkan ke artikel (seperti 5 di SO) dan menambahkannya langsung ke tabel artikel Anda.
Normalisasi DB memiliki kelebihan dan kekurangan, seperti hal-hal yang memasang kabel ke dalam satu tabel memiliki kelebihan dan kekurangan.
Tidak ada yang mengatakan Anda tidak bisa melakukan keduanya. Ini bertentangan dengan paradigma DB relasional untuk mengulang informasi, tetapi jika tujuannya adalah kinerja, Anda mungkin harus mematahkan paradigma tersebut.
sumber
Penerapan tiga tabel yang Anda usulkan akan berfungsi untuk pemberian tag.
Stack overflow menggunakan implementasi yang berbeda. Mereka menyimpan tag ke kolom varchar di tabel posting dalam teks biasa dan menggunakan pengindeksan teks lengkap untuk mengambil posting yang cocok dengan tag. Misalnya
posts.tags = "algorithm system tagging best-practices"
. Saya yakin Jeff telah menyebutkan ini di suatu tempat tetapi saya lupa di mana.sumber
Solusi yang diusulkan adalah yang terbaik -jika bukan satu-satunya cara yang dapat dipraktikkan- yang dapat saya pikirkan untuk menangani hubungan banyak-ke-banyak antara tag dan artikel. Jadi pilihan saya adalah 'ya, itu masih yang terbaik.' Saya akan tertarik pada alternatif apa pun.
sumber
Jika database Anda mendukung array yang dapat diindeks (seperti PostgreSQL, misalnya), saya akan merekomendasikan solusi yang sepenuhnya didenormalisasi - simpan tag sebagai array string pada tabel yang sama. Jika tidak, tabel sekunder yang memetakan objek ke tag adalah solusi terbaik. Jika Anda perlu menyimpan informasi tambahan terhadap tag, Anda dapat menggunakan tabel tag terpisah, tetapi tidak ada gunanya memperkenalkan gabungan kedua untuk setiap pencarian tag.
sumber
Saya ingin menyarankan MySQLicious yang dioptimalkan untuk kinerja yang lebih baik. Sebelumnya kekurangan dari solusi Toxi (3 tabel) adalah
Jika Anda memiliki jutaan pertanyaan, dan masing-masing memiliki 5 tag, maka akan ada 5 juta entri di tabel tagmap. Jadi pertama-tama kita harus menyaring 10 ribu entri tagmap berdasarkan pencarian tag, lalu menyaring lagi pertanyaan yang cocok dari 10 ribu itu. Jadi saat memfilter jika id artikal adalah numerik sederhana maka tidak apa-apa, tetapi jika itu jenis UUID (32 varchar) maka memfilter membutuhkan perbandingan yang lebih besar meskipun diindeks.
Solusi saya:
Setiap kali tag baru dibuat, miliki penghitung ++ (basis 10), dan konversikan penghitung tersebut menjadi base64. Sekarang setiap nama tag akan memiliki id base64. dan berikan id ini ke UI bersama dengan nama. Dengan cara ini Anda akan memiliki maksimal dua karakter hingga kami memiliki 4095 tag yang dibuat di sistem kami. Sekarang gabungkan beberapa tag ini ke dalam setiap kolom tag tabel pertanyaan. Tambahkan juga pembatas dan buat itu diurutkan.
Jadi tabel terlihat seperti ini
Saat membuat kueri, kueri di id alih-alih nama tag asli. Karena SORTED ,
and
kondisi pada tag akan lebih efisien (LIKE '%|a|%|c|%|f|%
).Perhatikan bahwa pembatas spasi tunggal tidak cukup dan kita memerlukan pembatas ganda untuk membedakan tag seperti
sql
danmysql
karenaLIKE "%sql%"
akan mengembalikanmysql
hasil juga. SeharusnyaLIKE "%|sql|%"
Saya tahu pencarian tidak diindeks tetapi tetap saja Anda mungkin telah diindeks pada kolom lain yang terkait dengan artikel seperti author / dateTime lain akan mengarah ke pemindaian tabel lengkap.
Akhirnya dengan solusi ini, tidak ada inner join yang dibutuhkan dimana jutaan record harus dibandingkan dengan 5 juta record pada kondisi join.
sumber
Catatan:
AUTO_INCREMENT
PK pengganti . Karenanya, ini lebih baik dari Scuttle.LIKE
dengan wild card terkemuka ; false hits pada substring)Diskusi terkait (untuk MySQL):
banyak: banyak optimasi tabel pemetaan
memerintahkan daftar
sumber