【问题标题】:How do I map tags to tag synonyms?如何将标签映射到标签同义词?
【发布时间】:2015-07-16 13:49:08
【问题描述】:

我正在构建一个用户将标签与帖子相关联的系统,这与 SO 不同。我在实现tag synonyms 时遇到了麻烦。

这里有一个名为标签的表格:

| TagName    |
|------------|
| Python     |
| JavaScript |
| Node       |

我还有一个叫TagSynonyms

| SynonymId | SourceTagName | TargetTagName |
|-----------|---------------|---------------|
| 1         | Py            | Python        |
| 2         | Python2       | Python        |

服务器使用Node实现,用户输入一些标签作为逗号分隔的字符串:

var input = 'Py,Flask'
var tags = request.tags.split(',');

在这种情况下,用户输入了标签 Py,根据 TagSynonyms 表,该标签应该映射到标签 Python .第二个标签 Flask 没有同义词,应该保持不变。

我设法使用命令式代码实现了这个功能:

tags.forEach(function (tag) {
  connection.query('SELECT TargetTagName FROM TagSynonyms WHERE SourceTagName = ?', tag, function(err, rows) {
    if (rows.length !== 0) {
      console.log(rows[0].TargetTagName);
    } else {
      console.log(tag);
    }
  });
});

这里是用户输入

['Py','Flask'] 

产生以下输出

Python
Flask

我想做的是,将此逻辑推迟到数据库引擎,因为我认为使用循环是一种代码味道。我还认为数据库引擎的性能会更高。执行此操作的合适查询是什么?

【问题讨论】:

  • 你可以SELECT TargetTagName FROM TagSynonyms WHERE SourceTagName IN ?, tags,在一个查询中从数据库中选择所有值
  • 同义词似乎是多余的
  • @Strawberry 是的,我也是这么想的。目前我不确定还有什么可以用作主键。
  • @vanadium23 我认为这将返回一个表,其中一行的值为 Python 而我想要一个两行的结果 Python 烧瓶。有什么想法吗?
  • @Angularnoob 我猜是什么问题,将查询重写为SELECT TargetTagName FROM TagSynonyms WHERE SourceTagName IN ('Py','Flask') OR TargetTagName IN ('Py','Flask') 将返回 Flask 和 Python

标签: javascript mysql sql node.js node-mysql


【解决方案1】:

您需要一个UNION 和一个加入:

  select TagName
    from Tags
    where TagName in (?,?,?,...)
union
  select TagName
    from Tags
    join TagSynonyms
      on Tags.TagName = TagSynonyms.TargetTagName
    where TagSynonyms.SourceTagName in (?,?,?,...)

请注意,union 可能会很慢,因为它会尝试删除重复项。如果您遇到这种情况,请使用 union all 并删除应用程序代码中的重复项。

(?,?,?,...) 代表输入值列表;检查您的 DB 驱动程序文档,了解避免 SQL 注入所需使用的确切语法。

更新:以下是 Node 中的实现:

var query = 
'SELECT TagName \
FROM Tags \
WHERE TagName IN (?) \
UNION \
SELECT TagName \
FROM Tags \
JOIN TagSynonyms \
  ON Tags.TagName = TagSynonyms.TargetTagName \
WHERE TagSynonyms.SourceTagName IN (?)'

connection.query(query, [tags, tags], function(err, rows) {
  tags = rows.map(function(row) { 
    return row.TagName
  });
});

【讨论】:

  • 我在 Workbench 中对此进行了测试,我认为它是理想的。我现在要在 Node 中尝试这个,我会回复你的。谢谢你,亚伦!
  • @Strawberry:如果没有第一次选择,您将不会为输入 Python 获得 Python。查询的结果是系统直接或通过别名知道的一组标签。如果您只想将别名转换为名称,则可以使用第二个查询。
  • @AaronDigulla 第一个输入是“Py”。您仍然不会得到“Flask”,因此应用程序无论如何都必须对丢失的结果进行一些后期处理。我不相信这比现有解决方案有任何优势。
  • @Strawberry 如果 Flask 已经在 Tags 表中,您确实会得到 Flask。我很想听听您对我当前解决方案的论点!
  • @Angularnoob 但它不是:“第二个标签,Flask 没有同义词,应该保持不变。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 2021-09-03
  • 2017-05-04
  • 2012-04-02
  • 2016-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多