Reenable the note search API

Add a postgress freetext index on the note comments, and enable
note searching using freetext matching.
This commit is contained in:
Tom Hughes 2014-01-15 19:58:58 +00:00
parent a4561fe89b
commit 45618726ef
5 changed files with 71 additions and 60 deletions

View file

@ -255,16 +255,11 @@ class NotesController < ApplicationController
# Get any conditions that need to be applied
@notes = closed_condition(Note.all)
@notes = @notes.joins(:comments).where("note_comments.body ~ ?", params[:q])
@notes = @notes.joins(:comments).where("to_tsvector('english', note_comments.body) @@ plainto_tsquery('english', ?)", params[:q])
# Find the notes we want to return
@notes = @notes.order("updated_at DESC").limit(result_limit).preload(:comments)
# Disable notes search until we can make it scalable
response.headers['Error'] = "Searching of notes is currently unavailable"
render :text => "", :status => :service_unavailable
return false
# Render the result
respond_to do |format|
format.rss { render :action => :index }

View file

@ -0,0 +1,11 @@
require 'migrate'
class AddTextIndexToNoteComments < ActiveRecord::Migration
def up
add_index :note_comments, [], :columns => "to_tsvector('english', body)", :method => "GIN", :name => "index_note_comments_on_body"
end
def down
remove_index :note_comments, :name => "index_note_comments_on_body"
end
end

View file

@ -3,6 +3,7 @@
--
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
@ -1797,6 +1798,13 @@ CREATE INDEX gpx_files_visible_visibility_idx ON gpx_files USING btree (visible,
CREATE UNIQUE INDEX index_client_applications_on_key ON client_applications USING btree (key);
--
-- Name: index_note_comments_on_body; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_note_comments_on_body ON note_comments USING gin (to_tsvector('english'::regconfig, body));
--
-- Name: index_note_comments_on_created_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
@ -2466,6 +2474,8 @@ INSERT INTO schema_migrations (version) VALUES ('20130328184137');
INSERT INTO schema_migrations (version) VALUES ('20131212124700');
INSERT INTO schema_migrations (version) VALUES ('20140115192822');
INSERT INTO schema_migrations (version) VALUES ('21');
INSERT INTO schema_migrations (version) VALUES ('22');

View file

@ -126,6 +126,9 @@ module ActiveRecord
if Hash === options and options[:lowercase]
quoted_column_names = quoted_column_names.map { |e| "LOWER(#{e})" }
end
if Hash === options and options[:columns]
quoted_column_names = quoted_column_names + Array[options[:columns]]
end
quoted_column_names = quoted_column_names.join(", ")
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} USING #{index_method} (#{quoted_column_names})"

View file

@ -638,76 +638,68 @@ class NotesControllerTest < ActionController::TestCase
def test_search_success
get :search, {:q => 'note 1', :format => 'xml'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/xml", @response.content_type
# assert_select "osm", :count => 1 do
# assert_select "note", :count => 1
# end
assert_response :success
assert_equal "application/xml", @response.content_type
assert_select "osm", :count => 1 do
assert_select "note", :count => 1
end
get :search, {:q => 'note 1', :format => 'json'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/json", @response.content_type
# js = ActiveSupport::JSON.decode(@response.body)
# assert_not_nil js
# assert_equal "FeatureCollection", js["type"]
# assert_equal 1, js["features"].count
assert_response :success
assert_equal "application/json", @response.content_type
js = ActiveSupport::JSON.decode(@response.body)
assert_not_nil js
assert_equal "FeatureCollection", js["type"]
assert_equal 1, js["features"].count
get :search, {:q => 'note 1', :format => 'rss'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/rss+xml", @response.content_type
# assert_select "rss", :count => 1 do
# assert_select "channel", :count => 1 do
# assert_select "item", :count => 1
# end
# end
assert_response :success
assert_equal "application/rss+xml", @response.content_type
assert_select "rss", :count => 1 do
assert_select "channel", :count => 1 do
assert_select "item", :count => 1
end
end
get :search, {:q => 'note 1', :format => 'gpx'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/gpx+xml", @response.content_type
# assert_select "gpx", :count => 1 do
# assert_select "wpt", :count => 1
# end
assert_response :success
assert_equal "application/gpx+xml", @response.content_type
assert_select "gpx", :count => 1 do
assert_select "wpt", :count => 1
end
end
def test_search_no_match
get :search, {:q => 'no match', :format => 'xml'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/xml", @response.content_type
# assert_select "osm", :count => 1 do
# assert_select "note", :count => 0
# end
assert_response :success
assert_equal "application/xml", @response.content_type
assert_select "osm", :count => 1 do
assert_select "note", :count => 0
end
get :search, {:q => 'no match', :format => 'json'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/json", @response.content_type
# js = ActiveSupport::JSON.decode(@response.body)
# assert_not_nil js
# assert_equal "FeatureCollection", js["type"]
# assert_equal 0, js["features"].count
assert_response :success
assert_equal "application/json", @response.content_type
js = ActiveSupport::JSON.decode(@response.body)
assert_not_nil js
assert_equal "FeatureCollection", js["type"]
assert_equal 0, js["features"].count
get :search, {:q => 'no match', :format => 'rss'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/rss+xml", @response.content_type
# assert_select "rss", :count => 1 do
# assert_select "channel", :count => 1 do
# assert_select "item", :count => 0
# end
# end
assert_response :success
assert_equal "application/rss+xml", @response.content_type
assert_select "rss", :count => 1 do
assert_select "channel", :count => 1 do
assert_select "item", :count => 0
end
end
get :search, {:q => 'no match', :format => 'gpx'}
assert_response :service_unavailable
# assert_response :success
# assert_equal "application/gpx+xml", @response.content_type
# assert_select "gpx", :count => 1 do
# assert_select "wpt", :count => 0
# end
assert_response :success
assert_equal "application/gpx+xml", @response.content_type
assert_select "gpx", :count => 1 do
assert_select "wpt", :count => 0
end
end
def test_search_bad_params