Wie kann ich eine „interessante Tags“-Funktion wie diese in Stack Overflow implementieren?
Lesezeit: 10 Minuten
guten Abend
Überprüfen Sie meine andere Frage mit Kopfgeld: Ähnliche Zahlenmuster in der Tabelle finden
Ich versuche, eine zu implementieren Interessante Tags Besonderheit. Als Referenz funktioniert es so auf SO:
Ich füge meine interessanten Tags (wie php, mysql, jquery und so weiter) in die “interessante” Liste ein.
Wenn dann eine der angezeigten Fragen einige der Tags in meiner Liste enthält, wird der Hintergrund orange.
Ich verstehe, wie man jQuery dazu verwendet (es gibt verwandte Fragen dazu), kann aber nicht herausfinden, wie man den Back-End-Teil mit MySQL implementiert!
Deshalb hier meine Frage: Wie wird das gemacht? Ich stelle mir das so vor:
In mysql gibt es für jedes Mitglied eine Zeile, nennen wir sie “interested_tags”.
Nachdem ich mein Tag durch Eingabe geschrieben und gesendet habe, wird es in eine Reihe “interested_tags” geschrieben.
Dann hat die Hauptseite eine Abfrage, die alle Antworten anzeigt, und sie überprüft immer die Tags der Frage mit meinen Tags, indem sie strpos wie folgt verwendet:
if(strpos($question_tags, $my_tags) === true) {
//and here will be made background orange
}
Denke ich richtig oder gibt es eine Möglichkeit?
EDIT: Also, können Sie mir ein Beispiel zeigen oder mir ein paar Tipps geben, wie ich das mit Many-to-Many-Beziehungen implementieren kann? Vielen Dank.
Trotz des Titels ist dies nicht eine frage an meta. Der Fragesteller fragt nicht was gemacht wird, sondern wie er kann, was eindeutig ein Programmierproblem ist.
– Ignacio Vazquez-Abrams
26. Mai 2010 um 16:57 Uhr
Wow Shoq, sehr schöne Bearbeitung, danke.
– guten Abend
26. Mai 2010 um 17:25 Uhr
Welchen Teil Ihrer Frage deckt meine Antwort nicht ab?
– Simen Echoholt
13. August 2010 um 8:13 Uhr
Sie könnten es so machen (alle interessanten Tags in einer Spalte, anstatt einer separaten Viele-Viele-Tabelle, wie Simen veranschaulicht), aber es gibt ein paar Nachteile: 1) Sie müssen das Parsen und Filtern selbst durchführen, anstatt es zuzulassen DB erledigt die Arbeit, 2) die Längenbeschränkung des Feldes kann unbequemer zu handhaben sein, 3) die Frage “Welche Benutzer denken, dass Tag YYY interessant ist?” ist teuer. Der Vorteil ist jedoch, dass die Suche des gesamten Satzes nach Benutzer-ID sehr schnell ist, da es sich nur um eine einzelne Spaltensuche handelt, nicht um eine Tabellenverknüpfung.
– Owen S.
13. August 2010 um 23:29 Uhr
Simen Echoholt
Wie in den anderen Antworten erwähnt, besteht höchstwahrscheinlich eine Viele-zu-Viele-Beziehung zwischen Benutzern und Tags, die als eigene Tabelle dargestellt wird. Ich habe eine SQL-Demo eines vereinfachten Falls erstellt. Das InterestingTags Tabelle ist die Tabelle, die verbindet, welcher Benutzer an welchen Tags interessiert ist.
/* Create tables */
CREATE TABLE User (id INT NOT NULL AUTO_INCREMENT, name varchar(50), PRIMARY KEY(id));
CREATE TABLE Tag (id INT NOT NULL AUTO_INCREMENT, name varchar(50), PRIMARY KEY(id));
CREATE TABLE InterestingTags (user_id INT NOT NULL REFERENCES User(id), tag_id INT NOT NULL REFERENCES Tag(id), PRIMARY KEY(user_id,tag_id));
/* Insert some data */
/* 3 users, 5 tags and some connections between users and tags */
INSERT INTO User (name) VALUES ('jQueryFreak'), ('noFavoriteMan'), ('generalist');
INSERT INTO Tag (name) VALUES ('jQuery'), ('php'), ('asp.net'), ('c#'), ('ruby');
INSERT INTO InterestingTags (user_id, tag_id) VALUES (1,1), (3,1), (3,2), (3,3), (3,4);
/* Select all the users and what tags they are interested in */
SELECT u.name, t.name FROM User u
LEFT JOIN InterestingTags it ON it.user_id = u.id
LEFT JOIN Tag t ON t.id = it.tag_id;
/* Select all tag ids that are interesting to user 3 ("generalist") */
SELECT tag_id FROM InterestingTags WHERE user_id = 3;
/*
Now let's introduce a questions table.
For simplicity, let's say a question can only have one tag.
There's really a many-to-many relationship here, too, as with user and tag
*/
CREATE TABLE Question (id INT NOT NULL AUTO_INCREMENT, title VARCHAR(50) NOT NULL, tag_id INT NOT NULL REFERENCES Tag(id), PRIMARY KEY(id));
/* Insert some questions */
INSERT INTO Question (title, tag_id) VALUES
('generating random numbers in php', 2), /*php question*/
('hiding divs in jQuery', 1), /*jQuery question*/
('how do i add numbers with jQuery', 1), /*jQuery question 2*/
('asp.net help', 3), /*asp.net question */
('c# question', 4), /*c# question */
('ruby question', 5); /*ruby question */
/* select all questions and what users are interested in them */
SELECT q.title, u.name FROM Question q
LEFT JOIN InterestingTags it ON it.tag_id = q.tag_id
LEFT JOIN User u ON u.id = it.user_id;
/* select all questions a user will be interested in. Here the user is jQueryFreak with id = 1 */
SELECT q.id, q.title FROM Question q
LEFT JOIN InterestingTags it ON it.tag_id = q.tag_id
LEFT JOIN User u ON u.id = it.user_id
WHERE u.id = 1;
/* Select all questions and indicate whether or not jQueryFreak (with id = 1) is interested in each one */
/* TODO: make SO question about how to do this as efficient as possible :) */
SELECT q.id, q.title,
(SELECT COUNT(*) FROM InterestingTags it
WHERE it.tag_id = q.tag_id AND it.user_id = 1)
AS is_interested
FROM Question q;
/* Let's add a many-to-many relationship between questions and tags.
Questions can now have many tags
*/
ALTER TABLE Question DROP COLUMN tag_id;
CREATE TABLE Question_Tag (
question_id INT NOT NULL REFERENCES Question (id),
tag_id INT NOT NULL REFERENCES Tag (id),
PRIMARY KEY (question_id, tag_id)
);
/* Insert relationships between questions and tags */
INSERT INTO Question_Tag VALUES
/* First the tags as in the above examples */
(1,2), (2,1), (3,1),(4,3),(5,4),(6,5),
/* And some more. ASP.NET question is also tagged C#
and php question is tagged jQuery */
(1,1), (4,4);
/* select all questions and what users are interested in them
(Some combinations will show up multiple times. This duplication is removed in the
two following queries but I didn't find a solution for it here)*/
SELECT q.title, u.name FROM Question q
LEFT JOIN Question_Tag qt ON qt.question_id = q.id /* <-- new join */
LEFT JOIN InterestingTags it ON it.tag_id = qt.tag_id
LEFT JOIN User u ON u.id = it.user_id;
/* select all questions a user will be interested in. Here the user is jQueryFreak with id = 1 */
SELECT q.id, q.title FROM Question q
LEFT JOIN Question_Tag qt ON qt.question_id = q.id /* <-- new join */
LEFT JOIN InterestingTags it ON it.tag_id = qt.tag_id
LEFT JOIN User u ON u.id = it.user_id
WHERE u.id = 1
GROUP BY q.id; /* prevent duplication of a question in the result list */
/* Select all questions and indicate whether or not jQueryFreak (with id = 1) is interested in each one */
/* STILL TODO: make SO question about how to do this as efficient as possible :) */
SELECT q.id, q.title,
(SELECT COUNT(*) FROM InterestingTags it
WHERE it.tag_id = qt.tag_id AND it.user_id = 1)
AS is_interested
FROM Question q
LEFT JOIN Question_Tag qt ON qt.question_id = q.id /* <-- new join */
GROUP BY q.id;
Update: PHP-Demo hinzugefügt. Denken Sie daran, Ihre MySQL-Konstanten zu ändern, bevor Sie die Demo ausführen
Dies führt dazu, dass zwei Abfragen an die DB ausgeführt werden:
Eine, die nach allen Fragen und ihren Tags fragt
Eine Frage, an welchen Tags der Benutzer interessiert ist.
Um eine Frage mit ihren Tags zu “markieren”, fügt sie a hinzu class für jedes Tag, zu dem es gehört – zB eine Frage, die mit getaggt ist jQuery (wobei jQuery die ID hat 1) und php (mit Ausweis 2) wird die Klassen haben tagged-1 und tagged-2.
Wenn Sie dies nun mit der anderen Abfrage kombinieren, um die interessanten Tags abzurufen, müssen Sie nur noch die Fragen mit Klassen auswählen, die den interessanten Tags entsprechen, und sie formatieren. Interessieren Sie sich beispielsweise für die Tags mit ID 1 und 3wäre es der folgende jQuery-Code $('.tagged-1, .tagged-3').addClass('interesting-tag');
<?php
const mysql_host = "localhost";
const mysql_username = "";
const mysql_password = "";
const mysql_database = "INTERESTINGTEST";
const user_id = 1; //what user is viewing the page?
class Question {
public $id;
public $title;
public $tags;
function __construct($id,$title) {
$this->id = $id;
$this->title = $title;
$this->tags = array();
}
}
class Tag {
public $id;
public $name;
function __construct($id,$name) {
$this->id = $id;
$this->name = $name;
}
}
/**************************
Getting info from database
****************************/
mysql_connect(mysql_host,mysql_username,mysql_password);
mysql_select_db(mysql_database);
//Fetch interesting tags
$result = mysql_query("SELECT tag_id FROM InterestingTags WHERE user_id = " . user_id);
$interesting_tags = array();
while($row = mysql_fetch_array($result))
{
$interesting_tags[] = $row['tag_id'];
}
//Fetch all questions and their tags
$query_select_questions="SELECT q.id AS q_id, q.title AS q_title, t.id AS t_id, t.name AS t_name FROM Question q
LEFT JOIN Question_Tag qt ON qt.question_id = q.id
LEFT JOIN Tag t ON t.id = qt.tag_id";
$result = mysql_query($query_select_questions);
$questions = array();
while($row = mysql_fetch_array($result))
{
$q_id = $row['q_id'];
$q_title = $row['q_title'];
$t_id = $row['t_id'];
$t_name = $row['t_name'];
if (!array_key_exists($q_id, $questions))
$questions[$q_id] = new Question($q_id, $q_title);
$questions[$q_id]->tags[] = new Tag($t_id, $t_name);
}
mysql_close();
/**************************
Write document
****************************/
?>
<style>
.question { padding:0px 5px 5px 5px; border:1px solid gray; margin-bottom: 10px; width:400px }
.interesting-tag { background-color: #FFEFC6 }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script>
var interesting_tags = [ <?php echo implode($interesting_tags,',') ?> ];
var tagclass_prefix = ".tagged-";
var tags_selector = tagclass_prefix + interesting_tags.join(", " + tagclass_prefix);
$(function() {
$(tags_selector).addClass("interesting-tag");
});
</script>
<?php
foreach ($questions as $q) {
$tagsIDs = array();
$tagNames = array();
foreach ($q->tags as $tag) {
$tagsIDs[] = $tag->id;
$tagNames[] = $tag->name;
}
$classValue = "tagged-" . implode($tagsIDs," tagged-");
$tagNames = implode($tagNames, ", ");
?>
<div id="question-<?php echo $q->id ?>" class="question <?php echo $classValue ?>">
<h3><?php echo $q->title ?></h3>
Tagged with <strong><?php echo $tagNames ?></strong>
</div>
<?php
}
?>
Erstellen Sie auch eine Tabelle für die Frage- und Tag-Beziehung.
– Rakesh Juyal
13. August 2010 um 13:07 Uhr
In mysql gibt es für jedes Mitglied eine Zeile, nennen wir sie “interested_tags”.
Wahrscheinlicher ist, dass es eine zusätzliche Tabelle gibt, die eine Viele-zu-Viele-Beziehung zwischen Benutzern und Tags darstellt. Mit einer anderen Tabelle, die Tags mit Fragen verknüpft.
Dann brauchen Sie nur eine Abfrage (oder wahrscheinlicher eine gespeicherte Prozedur), die die Tags eines Benutzers mit den Tags einer Frage vergleicht und ein boolesches Wahr oder Falsch zurückgibt.
Stack Overflow-Tags funktionieren mit mindestens * im Tag, also speichern Sie Ihre Tags in einem Array und iterieren Sie durch sie, indem Sie Musterabgleich verwenden (es spielt keine Rolle, ob Sie Glob, SQL oder Regex verwenden, solange der Benutzer weiß, was verwendet wird).
Das könnte dich aufklären. Wie Kelly sagte, erfolgt dies in Javascript, nachdem die Seite geladen wurde. Soweit ich das beurteilen kann, laden sie alle Tags für alle Fragen und diejenigen, die dieselben Tags wie auf der rechten Seite haben, werden hervorgehoben. Sehen
Aus der Art und Weise, wie die Seiten gerendert werden, habe ich vermutet, dass der Tag-Vergleich in JavaScript durchgeführt wird. Die Schritte wären also:
Abfrage nach interessanten Tags des Benutzers
Ergebnisse für clientseitiges JS verfügbar machen
JS iteriert über jede Frage und ändert ein Attribut basierend auf einer Übereinstimmung (einschließlich des Entfernens des Beitrags, wenn er mit einem „Ignoriert“-Tag übereinstimmt.
11462600cookie-checkWie kann ich eine „interessante Tags“-Funktion wie diese in Stack Overflow implementieren?yes
Trotz des Titels ist dies nicht eine frage an meta. Der Fragesteller fragt nicht was gemacht wird, sondern wie er kann, was eindeutig ein Programmierproblem ist.
– Ignacio Vazquez-Abrams
26. Mai 2010 um 16:57 Uhr
Wow Shoq, sehr schöne Bearbeitung, danke.
– guten Abend
26. Mai 2010 um 17:25 Uhr
Welchen Teil Ihrer Frage deckt meine Antwort nicht ab?
– Simen Echoholt
13. August 2010 um 8:13 Uhr
Sie könnten es so machen (alle interessanten Tags in einer Spalte, anstatt einer separaten Viele-Viele-Tabelle, wie Simen veranschaulicht), aber es gibt ein paar Nachteile: 1) Sie müssen das Parsen und Filtern selbst durchführen, anstatt es zuzulassen DB erledigt die Arbeit, 2) die Längenbeschränkung des Feldes kann unbequemer zu handhaben sein, 3) die Frage “Welche Benutzer denken, dass Tag YYY interessant ist?” ist teuer. Der Vorteil ist jedoch, dass die Suche des gesamten Satzes nach Benutzer-ID sehr schnell ist, da es sich nur um eine einzelne Spaltensuche handelt, nicht um eine Tabellenverknüpfung.
– Owen S.
13. August 2010 um 23:29 Uhr