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.
This commit is contained in:
Sam Saffron 2020-02-07 11:53:13 +11:00
parent 73931cfaab
commit 80da6a5620
2 changed files with 52 additions and 8 deletions

View File

@ -36,7 +36,8 @@ module KnowledgeExplorer
if tags_count == tag_filters.length if tags_count == tag_filters.length
tag_filters.each_with_index do |tag, index| 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}") results = results.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
end end
else else
@ -46,7 +47,22 @@ module KnowledgeExplorer
# filter results by search term # filter results by search term
if @filters[:search_term].present? 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 end
if @filters[:order] == "title" if @filters[:order] == "title"

View File

@ -3,10 +3,10 @@
require 'rails_helper' require 'rails_helper'
describe KnowledgeExplorer::KnowledgeExplorerController do describe KnowledgeExplorer::KnowledgeExplorerController do
let!(:category) { Fabricate(:category) } fab!(:category) { Fabricate(:category) }
let!(:topic) { Fabricate(:topic, category: category) } fab!(:topic) { Fabricate(:topic, category: category) }
let!(:topic2) { Fabricate(:topic, category: category) } fab!(:topic2) { Fabricate(:topic, category: category) }
let!(:tag) { Fabricate(:tag, topics: [topic], name: 'test') } fab!(:tag) { Fabricate(:tag, topics: [topic], name: 'test') }
before do before do
SiteSetting.tagging_enabled = true SiteSetting.tagging_enabled = true
@ -100,15 +100,43 @@ describe KnowledgeExplorer::KnowledgeExplorerController do
end end
context 'when searching' do context 'when searching' do
it 'should return a list filtered by search term in title' do before do
get "/knowledge-explorer.json?search=topic 1" 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) expect(response.status).to eq(200)
json = JSON.parse(response.body) json = JSON.parse(response.body)
topics = json['topics']['topic_list']['topics'] 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) expect(topics.size).to eq(1)
end end
end end
end end