Start work on flare as a plugin

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@520716 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Erik Hatcher 2007-03-21 02:24:58 +00:00
parent c537524e01
commit e10ac8f652
6 changed files with 347 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@ -0,0 +1,34 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the flare plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the flare plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Flare'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View File

@ -0,0 +1,13 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'flare'

View File

@ -0,0 +1,15 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Flare; end
require 'flare/context'
require 'flare/controller_extensions'

View File

@ -0,0 +1,121 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class Flare::Context
attr_accessor :queries, :filters, :facet_queries, :applied_facet_queries
attr_reader :facet_fields, :text_fields
def initialize(solr_config)
@solr_config = solr_config
@connection = Solr::Connection.new(@solr_config[:solr_url])
clear
@facet_queries = {} # name => {:queries => [], :filters => []}
@index_info = @connection.send(Solr::Request::IndexInfo.new)
excluded = @solr_config[:facets_exclude] ? @solr_config[:facets_exclude].collect {|e| e.to_s} : []
@facet_fields = @index_info.field_names.find_all {|v| v =~ /_facet$/} - excluded
@text_fields = @index_info.field_names.find_all {|v| v =~ /_text$/}
end
def clear
@queries = []
@filters = []
@applied_facet_queries = []
# this is cleared for development purposes - allowing flare to stay running but different Solr datasets swapping
@index_info = @connection.send(Solr::Request::IndexInfo.new)
excluded = @solr_config[:facets_exclude] ? @solr_config[:facets_exclude].collect {|e| e.to_s} : []
@facet_fields = @index_info.field_names.find_all {|v| v =~ /_facet$/} - excluded
@text_fields = @index_info.field_names.find_all {|v| v =~ /_text$/}
# facet_queries not cleared as their lifetime is different than constraints
end
def empty_constraints?
@queries.empty? && @filters.empty? && @applied_facet_queries.empty?
end
def search(start, max)
facet_queries = @facet_queries.collect do |k,v|
clauses = filter_queries(v[:filters])
clauses << build_boolean_query(v[:queries])
query = clauses.join(" AND ")
@facet_queries[k][:real_query] = query
query
end
qa = applied_facet_queries.collect {|map| q = @facet_queries[map[:name]][:real_query]; map[:negative] ? "-(#{q})" : q}
qa << build_boolean_query(@queries)
request = Solr::Request::Standard.new(:query => qa.join(" AND "),
:filter_queries => filter_queries(@filters),
:start => start,
:rows => max,
:facets => {
:fields => @facet_fields, :limit => 20 , :mincount => 1, :sort => :count,
:queries => facet_queries
},
:highlighting => {:field_list => @text_fields})
#TODO: call response.field_facets(??) - maybe field_facets should be return a higher level?
# logger.info({:query => query, :filter_queries => filters}.inspect)
@connection.send(request)
end
def retrieve_field_facets(field, limit=-1, prefix=nil)
req = Solr::Request::Standard.new(:query => build_boolean_query(@queries),
:filter_queries => filter_queries(@filters),
:facets => {:fields => [field],
:mincount => 1, :limit => limit, :prefix => prefix, :missing => true, :sort => :count
},
:rows => 0
)
results = @connection.send(req)
results.field_facets(field)
end
def to_s
<<-TO_S
------
Applied facet queries: #{applied_facet_queries.inspect}
Queries: #{queries.inspect}
Filters: #{filters.inspect}
Facet queries: #{facet_queries.inspect}
------
TO_S
end
private
def build_boolean_query(queries)
if queries.nil? || queries.empty?
query = "*:*"
else
query = queries.collect{|q| "#{q[:negative] ? '-' : ''}(#{q[:query]})"}.join(' AND ')
end
query
end
def filter_queries(filters)
filters.collect do |filter|
value = filter[:value]
if value != "[* TO *]"
value = "\"#{value}\""
end
"#{filter[:negative] ? '-' : ''}#{filter[:field]}:#{value}"
end
end
end

View File

@ -0,0 +1,153 @@
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Flare
module ActionControllerExtensions
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def flare(options={})
include Flare::ActionControllerExtensions::InstanceMethods
end
end
module InstanceMethods
# Assumes @flare is set by a before_filter
def index
session[:page] = params[:page].to_i if params[:page]
session[:page] = 1 if session[:page] <= 0
@results_per_page = 25
@start = (session[:page] - 1) * @results_per_page
@response = @flare.search(@start, @results_per_page)
end
def facet
puts "---- facet: #{params[:field]}"
@facets = @flare.retrieve_field_facets(params[:field])
end
def auto_complete_for_search_query
# TODO instead of "text", default to the default search field configured in schema.xml
@values = @flare.retrieve_field_facets("text", 5, params['search']['query'].downcase)
render :partial => 'suggest'
end
def add_query
@flare.queries << {:query => params[:search][:query]}
session[:page] = 1
redirect_to :action => 'index'
end
def update_query
logger.debug "update_query: #{params.inspect}"
@flare.queries[params[:index].to_i][:query] = params[:value]
session[:page] = 1
render :update do |page|
page.redirect_to '/browse'
end
end
def invert_query
q = @flare.queries[params[:index].to_i]
q[:negative] = !q[:negative]
session[:page] = 1
redirect_to :action => 'index'
end
def remove_query
@flare.queries.delete_at(params[:index].to_i)
session[:page] = 1
redirect_to :action => 'index'
end
def invert_filter
f = @flare.filters[params[:index].to_i]
f[:negative] = !f[:negative]
session[:page] = 1
redirect_to :action => 'index'
end
def remove_filter
@flare.filters.delete_at(params[:index].to_i)
session[:page] = 1
redirect_to :action => 'index'
end
def add_filter
@flare.filters << {:field => params[:field], :value => params[:value], :negative => (params[:negative] ? true : false)}
session[:page] = 1
redirect_to :action => 'index'
end
def add_saved_search
@flare.applied_facet_queries << {:name => params[:name], :negative => (params[:negative] ? true : false)}
redirect_to :action => 'index'
end
def remove_saved_constraint
@flare.applied_facet_queries.delete_at(params[:index].to_i)
session[:page] = 1
redirect_to :action => 'index'
end
def clear
@flare.clear
redirect_to :action => 'index'
end
def show_saved
query = @flare.facet_queries[params[:name]]
@flare.applied_facet_queries << {:name => params[:name], :negative => (params[:negative] ? true : false)}
index
render :action => 'index'
end
def save
@flare.facet_queries[params[:name]] = {:filters => @flare.filters.clone, :queries => @flare.queries.clone}
redirect_to :action => 'index'
end
def remove_saved_search
puts "---- BEFORE", @flare.to_s
@flare.facet_queries.delete(params[:name])
@flare.applied_facet_queries.delete_if {|f| params[:name] == f[:name]}
puts "---- AFTER", @flare.to_s
session[:page] = 1
redirect_to :action => 'index'
end
def invert_saved_constraint
f = @flare.applied_facet_queries[params[:index].to_i]
f[:negative] = !f[:negative]
session[:page] = 1
redirect_to :action => 'index'
end
end
end
end
module ActionController
class Base
include Flare::ActionControllerExtensions
end
end