From 80da6a56208ba89037403dfd904302c3386d0ac6 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Fri, 7 Feb 2020 11:53:13 +1100 Subject: [PATCH] FEATURE: search entire knowledge base body as well as title Previously search was only searching through the title of topics This introduces full text search. It also means we get automatic stemming which gives far better results. --- lib/knowledge_explorer/query.rb | 20 +++++++++- .../knowledge_explorer_controller_spec.rb | 40 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/knowledge_explorer/query.rb b/lib/knowledge_explorer/query.rb index 779f14b..eb21386 100644 --- a/lib/knowledge_explorer/query.rb +++ b/lib/knowledge_explorer/query.rb @@ -36,7 +36,8 @@ module KnowledgeExplorer if tags_count == tag_filters.length tag_filters.each_with_index do |tag, index| - sql_alias = ['t', index].join + # to_i to make it clear this is not an injection + sql_alias = "t#{index.to_i}" results = results.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}") end else @@ -46,7 +47,22 @@ module KnowledgeExplorer # filter results by search term if @filters[:search_term].present? - results = results.where('lower(title) LIKE ?', "%#{@filters[:search_term].downcase}%") + term = Search.prepare_data(@filters[:search_term]) + escaped_ts_query = Search.ts_query(term: term) + + results = results.where(<<~SQL) + topics.id IN ( + SELECT pp.topic_id FROM post_search_data pd + JOIN posts pp ON pp.id = pd.post_id AND pp.post_number = 1 + JOIN topics tt ON pp.topic_id = tt.id + WHERE + tt.id = topics.id AND + pp.deleted_at IS NULL AND + tt.deleted_at IS NULL AND + pp.post_type <> #{Post.types[:whisper].to_i} AND + pd.search_data @@ #{escaped_ts_query} + ) + SQL end if @filters[:order] == "title" diff --git a/spec/requests/knowledge_explorer_controller_spec.rb b/spec/requests/knowledge_explorer_controller_spec.rb index a6e6cb6..5165443 100644 --- a/spec/requests/knowledge_explorer_controller_spec.rb +++ b/spec/requests/knowledge_explorer_controller_spec.rb @@ -3,10 +3,10 @@ require 'rails_helper' describe KnowledgeExplorer::KnowledgeExplorerController do - let!(:category) { Fabricate(:category) } - let!(:topic) { Fabricate(:topic, category: category) } - let!(:topic2) { Fabricate(:topic, category: category) } - let!(:tag) { Fabricate(:tag, topics: [topic], name: 'test') } + fab!(:category) { Fabricate(:category) } + fab!(:topic) { Fabricate(:topic, category: category) } + fab!(:topic2) { Fabricate(:topic, category: category) } + fab!(:tag) { Fabricate(:tag, topics: [topic], name: 'test') } before do SiteSetting.tagging_enabled = true @@ -100,15 +100,43 @@ describe KnowledgeExplorer::KnowledgeExplorerController do end context 'when searching' do - it 'should return a list filtered by search term in title' do - get "/knowledge-explorer.json?search=topic 1" + before do + SearchIndexer.enable + end + + # no fab here otherwise will be missing from search + let!(:post) do + topic = Fabricate(:topic, title: "I love banana today", category: category) + Fabricate(:post, topic: topic, raw: "walking and running is fun") + end + + let!(:post2) do + topic = Fabricate(:topic, title: "I love the amazing tomorrow", category: category) + Fabricate(:post, topic: topic, raw: "I also eat bananas") + end + + it 'should correctly filter topics' do + get "/knowledge-explorer.json?search=banana" expect(response.status).to eq(200) json = JSON.parse(response.body) topics = json['topics']['topic_list']['topics'] + # ordered by latest for now + + expect(topics[0]["id"]).to eq(post2.topic_id) + expect(topics[1]["id"]).to eq(post.topic_id) + + expect(topics.size).to eq(2) + + get "/knowledge-explorer.json?search=walk" + + json = JSON.parse(response.body) + topics = json['topics']['topic_list']['topics'] + expect(topics.size).to eq(1) + end end end