324

タグ付けを実装する方法をいくつか聞いたことがあります。TagID と ItemID の間のマッピング テーブルを使用する (私には理にかなっていますが、スケーリングしますか?)、固定数の可能な TagID 列を ItemID に追加する (悪い考えのように思えます)、コンマで区切られたテキスト列にタグを保持する (サウンドクレイジーですが、うまくいく可能性があります)。誰かがスパース行列を推奨しているとさえ聞いたことがありますが、タグ名はどのように適切に成長するのでしょうか?

タグのベスト プラクティスを見逃していませんか?

4

6 に答える 6

448

3 つのテーブル (すべてのアイテムを格納するためのテーブル、すべてのタグを格納するためのテーブル、および 2 つの間の関係のためのテーブル) が適切にインデックス化され、適切なデータベースで外部キー セットが実行されていると、適切に機能し、適切にスケーリングされるはずです。

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID
于 2008-08-21T19:22:44.013 に答える
95

通常、私は Yaakov Ellis に同意しますが、この特別なケースでは別の実行可能な解決策があります。

2 つのテーブルを使用します。

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID

Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

これにはいくつかの大きな利点があります。

まず、開発がはるかに簡単になります。挿入と更新のための 3 つのテーブル ソリューションではitem、テーブルを検索して、Tag既にエントリがあるかどうかを確認する必要があります。次に、それらを新しいものと結合する必要があります。これは簡単な作業ではありません。

次に、クエリがより簡単になります (そしておそらくより高速になります)。実行する主なデータベース クエリは 3 つあります。すべてTagsを 1 つに出力しItem、タグ クラウドを描画し、1 つのタグ タイトルに対してすべてのアイテムを選択します。

1 つのアイテムのすべてのタグ:

3-テーブル:

SELECT Tag.Title 
  FROM Tag 
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 WHERE ItemTag.ItemID = :id

2-テーブル:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

タグクラウド:

3-テーブル:

SELECT Tag.Title, count(*)
  FROM Tag
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 GROUP BY Tag.Title

2-テーブル:

SELECT Tag.Title, count(*)
  FROM Tag
 GROUP BY Tag.Title

1 つのタグのアイテム:

3-テーブル:

SELECT Item.*
  FROM Item
  JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
  JOIN Tag ON ItemTag.TagID = Tag.TagID
 WHERE Tag.Title = :title

2-テーブル:

SELECT Item.*
  FROM Item
  JOIN Tag ON Item.ItemID = Tag.ItemID
 WHERE Tag.Title = :title

ただし、いくつかの欠点もあります。データベース内でより多くのスペースが必要になる可能性があり (これにより、より多くのディスク操作が発生し、速度が低下する可能性があります)、正規化されていないため、不整合が生じる可能性があります。

タグの性質上、タグは通常非常に小さいため、サイズの増加はそれほど大きくないため、サイズの議論はそれほど強力ではありません。タグ タイトルのクエリは、各タグを 1 回だけ含む小さなテーブルではるかに高速であると主張することができますが、これは確かに真実です。しかし、参加する必要がないことによる節約と、それらに優れたインデックスを構築できるという事実を考慮すると、これを簡単に補うことができます. もちろん、これは使用しているデータベースのサイズに大きく依存します。

矛盾の議論も少し議論の余地があります。タグはフリー テキスト フィールドであり、「すべてのタグの名前を「foo」から「bar」に変更する」などの期待される操作はありません。

だからtldr:私は2テーブルのソリューションに行きます。(実際、そうするつもりです。この記事は、それに対する有効な議論があるかどうかを確認するために見つけました。)

于 2013-09-20T18:37:33.070 に答える
39

couchdb などの map-reduce をサポートするデータベースを使用している場合は、プレーン テキスト フィールドまたはリスト フィールドにタグを格納するのが実際に最善の方法です。例:

tagcloud: {
  map: function(doc){ 
    for(tag in doc.tags){ 
      emit(doc.tags[tag],1) 
    }
  }
  reduce: function(keys,values){
    return values.length
  }
}

これを group=true で実行すると、結果がタグ名でグループ化され、タグが検出された回数も返されます。これは、テキスト内の単語の出現回数を数えるのと非常によく似ています。

于 2008-09-07T19:41:11.363 に答える
13

タグを格納するために単一の書式設定されたテキスト列 [1] を使用し、これをインデックス化するために有能な全文検索エンジンを使用します。そうしないと、ブールクエリを実装しようとすると、スケーリングの問題が発生します。

持っているタグの詳細が必要な場合は、増分的に維持されるテーブルで追跡するか、バッチ ジョブを実行して情報を抽出できます。

[1] 一部の RDBMS はネイティブの配列型を提供しており、これは解析手順を必要としないため、ストレージにさらに適している可能性がありますが、全文検索で問題が発生する可能性があります。

于 2008-09-07T11:47:34.983 に答える
9

私は常にタグを別のテーブルに保管してから、マッピングテーブルを作成しました。もちろん、私は本当に大規模なことをしたこともありません。

「タグ」テーブルとマップ テーブルがあると、タグ クラウドなどを生成するのが非常に簡単になります。SQL を簡単にまとめて、各タグの使用頻度を含むタグのリストを取得できるからです。

于 2008-08-21T19:23:32.360 に答える
-2

次のデザインをお勧めします: Item Table: Itemid, taglist1, taglist2
これは高速で、アイテム レベルでデータを簡単に保存および取得できます。

並行して別のテーブルを作成します。タグ タグはタグの一意の識別子を作成しません。100 個のアイテムを含む 2 番目の列のスペースが不足すると、別の行が作成されます。

タグのアイテムを検索している間、それは超高速になります。

于 2015-11-28T09:51:15.113 に答える