# -*- mode: ruby; coding: utf-8 -*- base_dir = File.join(File.dirname(__FILE__), "..", "..") $LOAD_PATH.unshift(File.join(base_dir, "ext")) $LOAD_PATH.unshift(File.join(base_dir, "lib")) require 'rubygems' require 'rack' require 'groonga' use Rack::CommonLogger use Rack::Static, :urls => ["/css", "/images"], :root => "public" Groonga::Database.new("data/database") class Searcher include Rack::Utils def initialize @documents = Groonga::Context.default["documents"] end def call(env) request = Rack::Request.new(env) response = Rack::Response.new response["Content-Type"] = "text/html" response.write(<<-EOH) groongaで全文検索

groongaで全文検索

EOH render_search_box(request, response) render_search_result(request, response) response.write(<<-EOF)
EOF response.to_a end private def query(request) request['query'] || '' end def words(request) query(request).split end def render_search_box(request, response) response.write(<<-EOF)

groonga

EOF end def render_search_result(request, response) _words = words(request) if _words.empty? records = [] response.write(<<-EOS)

Rubyでgroonga使って全文検索

EOS else offset = 0 options = {} before = Time.now records = @documents.select do |record| expression = nil _words.each do |word| sub_expression = record["content"] =~ word if expression.nil? expression = sub_expression else expression &= sub_expression end end expression end total_records = records.size records = records.sort([[".:score", "descending"], [".last-modified", "descending"]], :limit => 20) elapsed = Time.now - before response.write(<<-EOS)

#{escape_html(query(request))}の検索結果: #{total_records}件中 #{total_records.zero? ? 0 : offset + 1} - #{offset + records.size} 件(#{elapsed}秒)

EOS end response.write("
\n") records.each do |record| render_record(request, response, record) end response.write("
\n") end def render_record(request, response, record) response.write("
\n") href = escape_html(record['.path']) title = escape_html(record['.title']) last_modified = escape_html(record['.last-modified'].iso8601) score = record.score response.write("

#{title}(#{score})

\n") render_snippet(request, response, record) response.write(<<-EOM)

#{unescape(href)} - #{last_modified}

EOM response.write("
\n") end def render_snippet(request, response, record) open_tag = "" close_tag = "" snippet = Groonga::Snippet.new(:width => 100, :default_open_tag => open_tag, :default_close_tag => close_tag, :html_escape => true, :normalize => true) words(request).each do |word| snippet.add_keyword(word) end separator = "\n...\n" response.write(<<-EOS)

#{snippet.execute(record[".content"]).join(separator)}

EOS end end run Searcher.new