active_lucene 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +64 -0
- data/Rakefile +47 -0
- data/lib/active_lucene.rb +31 -0
- data/lib/active_lucene/analyzer.rb +7 -0
- data/lib/active_lucene/document.rb +70 -0
- data/lib/active_lucene/index.rb +9 -0
- data/lib/active_lucene/query.rb +28 -0
- data/lib/active_lucene/searcher.rb +33 -0
- data/lib/active_lucene/term.rb +7 -0
- data/lib/active_lucene/writer.rb +24 -0
- metadata +64 -0
data/README.textile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
h2. ABOUT:
|
2
|
+
|
3
|
+
ActiveLucene is an ActiveRecord/ActiveModel's like interface to Apache Lucene, with support for dynamic attributes, pagination, highlighting and Lucene's query syntax.
|
4
|
+
|
5
|
+
ActiveLucene was extracted from Lunr:
|
6
|
+
|
7
|
+
http://github.com/dcrec1/lunr
|
8
|
+
|
9
|
+
ActiveLucene works with JRuby like this:
|
10
|
+
|
11
|
+
<pre><code>class Advertise < ActiveLucene::Document
|
12
|
+
end
|
13
|
+
|
14
|
+
Advertise.create! :param1 => 'value 1', :param2 => 'value 2'
|
15
|
+
|
16
|
+
Advertise.find :all
|
17
|
+
Advertise.find "5"
|
18
|
+
|
19
|
+
Advertise.search "value*"
|
20
|
+
Advertise.search "param2:'value 2' AND param3:lorem"
|
21
|
+
Advertise.search "param2:value OR param3:lorem"
|
22
|
+
|
23
|
+
Advertise.search :param1 => 'value 1', :param2 => 'value'
|
24
|
+
|
25
|
+
Advertise.serach(:param1 => 'va?ue').first.highlight
|
26
|
+
|
27
|
+
Advertise.serach(:param1 => 'va?ue').total_pages</code></pre>
|
28
|
+
|
29
|
+
Advertise#search accepts as a parameter any query supported by Lucene. For more information:
|
30
|
+
|
31
|
+
http://lucene.apache.org/java/2_3_2/queryparsersyntax.html
|
32
|
+
|
33
|
+
Note that you don't need to specify attributes, they are dynamic!
|
34
|
+
|
35
|
+
The pagination is supposed to be compatible with will_paginate:
|
36
|
+
|
37
|
+
http://github.com/mislav/will_paginate
|
38
|
+
|
39
|
+
For more examples, please refer to the specs.
|
40
|
+
|
41
|
+
h2. LICENSE:
|
42
|
+
|
43
|
+
(The MIT License)
|
44
|
+
|
45
|
+
Copyright (c) 2010
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
'Software'), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/specification'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
GEM = "active_lucene"
|
8
|
+
GEM_VERSION = "0.5.0"
|
9
|
+
SUMMARY = "ActiveRecord/ActiveModel's like interface for Lucene"
|
10
|
+
AUTHOR = "Diego Carrion"
|
11
|
+
EMAIL = "dc.rec1@gmail.com"
|
12
|
+
HOMEPAGE = "http://www.diegocarrion.com"
|
13
|
+
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = GEM
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.summary = SUMMARY
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
s.files = FileList['lib/**/*.rb', '[A-Z]*'].to_a
|
22
|
+
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new do |t|
|
29
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
t.spec_opts = %w(-fs --color)
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
34
|
+
pkg.gem_spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Install the gem locally"
|
38
|
+
task :install => [:package] do
|
39
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Create a gemspec file"
|
43
|
+
task :make_spec do
|
44
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
45
|
+
file.puts spec.to_ruby
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
Dir[File.expand_path(File.dirname(__FILE__) + "/*.jar")].each { |path| require path.split('/').last.gsub('.jar', '') }
|
6
|
+
import org.apache.lucene.document.Field
|
7
|
+
import org.apache.lucene.store.FSDirectory
|
8
|
+
import org.apache.lucene.index.IndexWriter
|
9
|
+
import org.apache.lucene.analysis.standard.StandardAnalyzer
|
10
|
+
import org.apache.lucene.queryParser.standard.StandardQueryParser
|
11
|
+
|
12
|
+
import org.apache.lucene.search.IndexSearcher
|
13
|
+
import org.apache.lucene.search.BooleanClause
|
14
|
+
import org.apache.lucene.search.BooleanQuery
|
15
|
+
import org.apache.lucene.search.MatchAllDocsQuery
|
16
|
+
import org.apache.lucene.search.WildcardQuery
|
17
|
+
|
18
|
+
import org.apache.lucene.search.highlight.QueryScorer
|
19
|
+
import org.apache.lucene.search.highlight.Highlighter
|
20
|
+
|
21
|
+
import org.apache.lucene.util.Version
|
22
|
+
|
23
|
+
APP_ROOT ||= RAILS_ROOT if defined?(RAILS_ROOT)
|
24
|
+
APP_ENV ||= RAILS_ENV if defined?(RAILS_ENV)
|
25
|
+
|
26
|
+
%w(analyzer document index query searcher term writer).each { |name| require "active_lucene/#{name}" }
|
27
|
+
|
28
|
+
module ActiveLucene
|
29
|
+
ID = 'id'
|
30
|
+
ALL = '_all'
|
31
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveLucene
|
2
|
+
class Document
|
3
|
+
PER_PAGE = 20
|
4
|
+
|
5
|
+
attr_reader :attributes, :id, :highlight
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
@attributes = attributes.stringify_keys
|
9
|
+
@highlight = @attributes.delete('highlight')
|
10
|
+
@id = @attributes.delete('id') || object_id.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def save
|
14
|
+
document = org.apache.lucene.document.Document.new
|
15
|
+
_all = []
|
16
|
+
@attributes.each do |key, value|
|
17
|
+
document.add Field.new key, value, Field::Store::YES, Field::Index::ANALYZED
|
18
|
+
_all << value
|
19
|
+
end
|
20
|
+
document.add Field.new ID, @id, Field::Store::YES, Field::Index::NOT_ANALYZED
|
21
|
+
document.add Field.new ALL, _all.join(' '), Field::Store::NO, Field::Index::ANALYZED
|
22
|
+
Writer.write document
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy
|
26
|
+
Writer.delete @id
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_attributes(new_attributes)
|
30
|
+
destroy
|
31
|
+
self.class.create! attributes.merge(new_attributes.merge(:id => @id))
|
32
|
+
end
|
33
|
+
alias :update_attributes! :update_attributes
|
34
|
+
|
35
|
+
def to_param
|
36
|
+
@id
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.create!(attributes)
|
40
|
+
returning new(attributes) do |model|
|
41
|
+
model.save
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.find(param)
|
46
|
+
if param.instance_of? Symbol
|
47
|
+
search :all
|
48
|
+
else
|
49
|
+
search(:id => param).first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.search(param)
|
54
|
+
search = Searcher.search(param)
|
55
|
+
results = search.attributes.map { |attributes| new attributes }
|
56
|
+
results.instance_eval "def total_pages; #{search.total_pages}; end;"
|
57
|
+
results
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.columns
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def method_missing(method_name, *args)
|
67
|
+
@attributes[method_name.to_s]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActiveLucene
|
2
|
+
class Query
|
3
|
+
|
4
|
+
def self.for(param)
|
5
|
+
if param.instance_of? Hash
|
6
|
+
for_attributes param
|
7
|
+
elsif param.instance_of? Symbol
|
8
|
+
MatchAllDocsQuery.new
|
9
|
+
else
|
10
|
+
for_string param
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def self.for_attributes(attributes)
|
17
|
+
returning BooleanQuery.new do |query|
|
18
|
+
attributes.each do |key, value|
|
19
|
+
query.add WildcardQuery.new(ActiveLucene::Term.for(key, value)), BooleanClause::Occur::MUST
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.for_string(string)
|
25
|
+
StandardQueryParser.new(Analyzer.new).parse(string, ALL)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ActiveLucene
|
2
|
+
class Searcher < IndexSearcher
|
3
|
+
include Index
|
4
|
+
|
5
|
+
attr_reader :attributes, :total_pages
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super directory, true
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.search(param)
|
12
|
+
returning new do |searcher|
|
13
|
+
searcher.search param
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def search(param)
|
18
|
+
query = Query.for(param)
|
19
|
+
top_docs = super(query, nil, Document::PER_PAGE)
|
20
|
+
@attributes = top_docs.scoreDocs.map do |score_doc|
|
21
|
+
attributes = {}
|
22
|
+
doc(score_doc.doc).fields.each do |field|
|
23
|
+
attributes.store field.name, field.string_value
|
24
|
+
highlight = Highlighter.new(QueryScorer.new(query)).get_best_fragment(Analyzer.new, ALL, field.string_value)
|
25
|
+
attributes[:highlight] = highlight if highlight
|
26
|
+
end
|
27
|
+
attributes
|
28
|
+
end
|
29
|
+
@total_pages = (top_docs.totalHits / Document::PER_PAGE.to_f).ceil
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActiveLucene
|
2
|
+
class Writer < IndexWriter
|
3
|
+
include Index
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
overwrite = Dir[PATH + '/*'].size < 1
|
7
|
+
super directory, Analyzer.new, overwrite, IndexWriter::MaxFieldLength::UNLIMITED
|
8
|
+
yield self
|
9
|
+
close
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.write(document)
|
13
|
+
new do |index|
|
14
|
+
index.add_document document
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.delete(id)
|
19
|
+
new do |index|
|
20
|
+
index.delete_documents ActiveLucene::Term.for(ID, id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_lucene
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Diego Carrion
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-23 00:00:00 -02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: dc.rec1@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/active_lucene/analyzer.rb
|
26
|
+
- lib/active_lucene/document.rb
|
27
|
+
- lib/active_lucene/index.rb
|
28
|
+
- lib/active_lucene/query.rb
|
29
|
+
- lib/active_lucene/searcher.rb
|
30
|
+
- lib/active_lucene/term.rb
|
31
|
+
- lib/active_lucene/writer.rb
|
32
|
+
- lib/active_lucene.rb
|
33
|
+
- Rakefile
|
34
|
+
- README.textile
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://www.diegocarrion.com
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.3.5
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: ActiveRecord/ActiveModel's like interface for Lucene
|
63
|
+
test_files: []
|
64
|
+
|