Eviepayne
(vladtheimplier)
21.Апрель.2025 01:08:51
1
При поиске на моём форуме по запросу tags:tag1, если tag1 является синонимом для tag-one, результаты не находятся, и пост с тегом tag-one не отображается.
1 лайк
Eviepayne
(vladtheimplier)
22.Апрель.2025 13:16:25
3
Я считаю, что это, вероятно, не является запланированным поведением, поэтому я помечу это как ошибку.
sam
(Sam Saffron)
23.Апрель.2025 05:30:23
4
Понятно, здесь, вероятно, стоит добавить обработку синонимов, согласен.
Добавляю метку pr-welcome на случай, если сообщество захочет помочь. Поиск полностью изолирован, поэтому написание тестов для него должно быть очень простым.
2 лайка
Moin
12.Февраль.2026 09:32:16
5
Исправлено
Теперь все работает:
Поиск по тегу:howto
Поиск по тегу:how-to
Поиск по #howto
Поиск по #how-to
main ← fix/tag-synonyms-in-search
merged 07:57AM - 09 Feb 26 UTC
What is the problem?
Discourse allows admins to mark a tag as a synonym of anot… her tag. For
example, "brunch" can be made a synonym of "lunch". When this happens,
all topics tagged with "brunch" are automatically retagged with "lunch",
and the `tags.target_tag_id` column on the synonym tag record is set to
point to the target tag.
However, several code paths did not account for synonyms:
1. **Search:** `Search#search_tags` and the hashtag advanced filter did
not resolve synonyms. When a user searched using a synonym name (e.g.
`tags:brunch`, `tags:brunch+eggs`, or `#brunch`), no results were
returned because:
- The `tags:` comma path queries `topic_tags` joined with `tags` by
name, but topics are tagged with the target tag "lunch", not the
synonym "brunch".
- The `tags:` plus path aggregates tag names per topic into a
tsvector and matches against the searched name, but the aggregated
names are target tag names, so "brunch" never matches.
- The `#` hashtag path picks the synonym tag's own `id` and queries
`topic_tags` by that ID, but topics store the target tag's ID.
2. **Filter route:** `TopicsFilter#tag_ids_from_tag_names` concatenated
both the synonym's own ID and the target tag ID. For match-all
queries (e.g. `tag:brunch`), this required a topic to have both IDs
in `topic_tags`, which never happens since only the target tag ID is
stored. For negation queries (e.g. `-tag:brunch`), the exclusion
targeted the synonym ID rather than the target, so no topics were
excluded.
What is the solution?
In `Search#search_tags`, add a synonym resolution step before the
existing comma/plus branching logic. It splits the match string into
individual tag names, queries for any that are synonyms via
`Tag.where_name(tag_names).where.not(target_tag_id: nil)`, builds a
name mapping, and replaces synonym names with their target tag names.
The replacement operates on the split array elements rather than using
substring replacement to avoid corrupting tag names that may contain
other tag names as substrings.
In the hashtag advanced filter, pick both `:id` and `:target_tag_id`
from the tag lookup and prefer `target_tag_id` when present, so the
query uses the target tag's ID instead of the synonym's own ID.
In `TopicsFilter#tag_ids_from_tag_names`, replace the transpose/concat
approach with `.map { |id, target_id| target_id || id }` to resolve
each tag to its canonical ID — the target for synonyms, or the tag's
own ID otherwise.
A partial index on `tags.target_tag_id` is added (scoped to
`WHERE target_tag_id IS NOT NULL`) to support efficient synonym lookups.
2 лайка
nat
(Natalie T)
Закрыл(а) тему
14.Февраль.2026 00:00:49
6
Эта тема была автоматически закрыта через 38 часов. Новые ответы больше не принимаются.