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 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,7 @@
1
+ module ActiveLucene
2
+ class Analyzer < StandardAnalyzer
3
+ def initialize
4
+ super Version::LUCENE_30
5
+ end
6
+ end
7
+ 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,9 @@
1
+ module ActiveLucene
2
+ module Index
3
+ PATH = "#{APP_ROOT}/db/lucene/#{APP_ENV}"
4
+
5
+ def directory
6
+ FSDirectory.open java.io.File.new(PATH)
7
+ end
8
+ end
9
+ 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,7 @@
1
+ module ActiveLucene
2
+ class Term
3
+ def self.for(name, value)
4
+ org.apache.lucene.index.Term.new name.to_s, value.to_s.downcase
5
+ end
6
+ end
7
+ 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
+