diff options
author | Seb Bacon <seb.bacon@gmail.com> | 2012-01-17 12:50:30 +0000 |
---|---|---|
committer | Seb Bacon <seb.bacon@gmail.com> | 2012-01-17 12:53:52 +0000 |
commit | c8a68219c541840b5c5f56cd75c1e84de6c15fe5 (patch) | |
tree | 9b1f062ba77a19b63c09a90710004959465c470b | |
parent | 3b0222d887e2ef1bd508e505b2327f8c2acac1d3 (diff) |
Actually do a proper ORed and partial match query, rather than fix parsing errors ad hoc as I find them that result from the workaround code. Fixes #328 (for good, I hope).
-rw-r--r-- | app/controllers/application_controller.rb | 28 | ||||
-rw-r--r-- | spec/controllers/request_controller_spec.rb | 14 | ||||
-rw-r--r-- | vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb | 15 |
3 files changed, 39 insertions, 18 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f6068120d..0c8544932 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -366,23 +366,31 @@ class ApplicationController < ActionController::Base return (params[:page] || "1").to_i end def perform_search_typeahead(query, model) - # strip out unintended search operators - see - # https://github.com/sebbacon/alaveteli/issues/328 - # XXX this is a result of the OR hack below -- should fix by - # allowing a parameter to perform_search to control the - # default operator! - query = query.strip.gsub(/(\s-\s|&|\(|\))/, "") - query = query.split(/ +(?![-+]+)/) - if query.last.nil? || query.last.strip.length < 3 + query_words = query.split(/ +(?![-+]+)/) + if query_words.last.nil? || query_words.last.strip.length < 3 xapian_requests = nil else - query = query.join(' OR ') # XXX: HACK for OR instead of default AND! if model == PublicBody collapse = nil elsif model == InfoRequestEvent collapse = 'request_collapse' end - xapian_requests = perform_search([model], query, 'relevant', collapse, 5) + options = { + :offset => 0, + :limit => 5, + :sort_by_prefix => nil, + :sort_by_ascending => true, + :collapse_by_prefix => collapse, + } + ActsAsXapian.readable_init + old_default_op = ActsAsXapian.query_parser.default_op + ActsAsXapian.query_parser.default_op = Xapian::Query::OP_OR + user_query = ActsAsXapian.query_parser.parse_query( + query, + Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_PARTIAL | + Xapian::QueryParser::FLAG_SPELLING_CORRECTION) + xapian_requests = ActsAsXapian::Search.new([model], query, options, user_query) + ActsAsXapian.query_parser.default_op = old_default_op end return xapian_requests end diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 40cb168f4..dcdacc29c 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -450,7 +450,9 @@ describe RequestController, "when searching for an authority" do "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ", "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the", "NHS Ayrshire & Arran", - " cardiff"] + " cardiff", + "Foo * bax", + "qux ~ quux"] lambda { get :select_authority, :query => phrase }.should_not raise_error(StandardError) @@ -1518,12 +1520,20 @@ describe RequestController, "when doing type ahead searches" do assigns[:xapian_requests].should be_nil end + it "should do partial matches for longer words" do + get :search_typeahead, :q => "chick" + response.should render_template('request/_search_ahead.rhtml') + assigns[:xapian_requests].results.size.should ==1 + end + it "should not give an error when user users unintended search operators" do for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo", "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ", "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the", "NHS Ayrshire & Arran", - "uda ( units of dent"] + "uda ( units of dent", + "frob * baz", + "bar ~ qux"] lambda { get :search_typeahead, :q => phrase }.should_not raise_error(StandardError) diff --git a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb index 45e412e0e..38bfb7c98 100644 --- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb +++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb @@ -274,7 +274,7 @@ module ActsAsXapian ActsAsXapian.enquire.sort_by_relevance! else value = ActsAsXapian.values_by_prefix[sort_by_prefix] - raise "couldn't find prefix '" + sort_by_prefix + "'" if value.nil? + raise "couldn't find prefix '" + sort_by_prefix.to_s + "'" if value.nil? ActsAsXapian.enquire.sort_by_value_then_relevance!(value, sort_by_ascending) end if collapse_by_prefix.nil? @@ -420,7 +420,7 @@ module ActsAsXapian # User]. Can take a single model class, or you can express the model # class names in strings if you like. # query_string - user inputed query string, with syntax much like Google Search - def initialize(model_classes, query_string, options = {}) + def initialize(model_classes, query_string, options = {}, user_query = nil) # Check parameters, convert to actual array of model classes new_model_classes = [] model_classes = [model_classes] if model_classes.class != Array @@ -439,10 +439,13 @@ module ActsAsXapian # Construct query which only finds things from specified models model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s}) - user_query = ActsAsXapian.query_parser.parse_query(self.query_string, - Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | - Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD | - Xapian::QueryParser::FLAG_SPELLING_CORRECTION) + if user_query.nil? + user_query = ActsAsXapian.query_parser.parse_query( + self.query_string, + Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | + Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD | + Xapian::QueryParser::FLAG_SPELLING_CORRECTION) + end self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, user_query) # Call base class constructor |