Skip to content

Commit

Permalink
Impl. support for indexing/query ruby Date [#2 state:open]
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasronge committed Dec 15, 2008
1 parent e8b4824 commit 3ec34b1
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 38 deletions.
62 changes: 37 additions & 25 deletions lib/lucene/field_info.rb
@@ -1,9 +1,10 @@
require 'date'

module Lucene
class ConversionNotSupportedException < StandardError; end

class FieldInfo
DEFAULTS = {:store => false, :type => String}.freeze
TYPE_CONVERSION_TABLE = { Fixnum => :to_i, Float => :to_f, String => :to_s }
DEFAULTS = {:store => false, :type => String}.freeze

def initialize(values = {})
@info = DEFAULTS.dup
Expand All @@ -15,7 +16,6 @@ def dup
FieldInfo.new(@info)
end


def [](key)
@info[key]
end
Expand All @@ -24,32 +24,45 @@ def []=(key,value)
@info[key] = value
end

def java_field(key, value)
store = store? ? org.apache.lucene.document.Field::Store::YES : org.apache.lucene.document.Field::Store::NO
def java_field(key, value)
store = store? ? org.apache.lucene.document.Field::Store::YES : org.apache.lucene.document.Field::Store::NO
cvalue = convert_to_lucene(value)
token_type = tokenized? ? org.apache.lucene.document.Field::Index::ANALYZED : org.apache.lucene.document.Field::Index::NOT_ANALYZED
$LUCENE_LOGGER.debug{"java_field store=#{store} key='#{key.to_s}' value='#{cvalue}' token_type=#{token_type}"}
org.apache.lucene.document.Field.new(key.to_s, cvalue, store, token_type ) #org.apache.lucene.document.Field::Index::NO_NORMS)
end

def convert_to_ruby(value)
method = TYPE_CONVERSION_TABLE[@info[:type]]
raise ConversionNotSupportedException.new("Can't convert key '#{key}' since method '#{method}' is missing") unless value.respond_to? method
if (value.kind_of?(Array))
value.collect{|v| v.send(method)}
else
value.send(method)
if (value.kind_of?(Array))
value.collect{|v| convert_to_ruby(v)}
else case @info[:type].to_s
when NilClass.to_s then "" # TODO, should we accept nil values in indexes ?
when String.to_s then value.to_s
when Fixnum.to_s then value.to_i
when Float.to_s then value.to_f
when Date.to_s
return value if value.kind_of? Date
date = org.apache.lucene.document.DateTools.stringToDate(value)
seconds_since_1970 = date.getTime / 1000
Date.new(*Time.at(seconds_since_1970).to_a[3 .. 5].reverse)
else
raise ConversionNotSupportedException.new("Can't convert key '#{value}' of with type '#{@info[:type].class.to_s}'")
end
end
end

def convert_to_lucene(value)
if (value.kind_of?(Array))
def convert_to_lucene(value)
if (value.kind_of?(Array))
value.collect{|v| convert_to_lucene(v)}
else
case @info[:type].to_s # otherwise it will match Class
when Fixnum.to_s then sprintf('%011d',value) # TODO: configurable
when Float.to_s then sprintf('%024.12f', value) # TODO: configurable
when Bignum.to_s then sprintf('%024d, value')
when Date.to_s
t = Time.gm(value.year, value.month, value.day)
d = t.to_i * 1000
org.apache.lucene.document.DateTools.timeToString(d,org.apache.lucene.document.DateTools::Resolution::DAY )
else value.to_s
end
end
Expand All @@ -59,18 +72,18 @@ def convert_to_query(key,value)
if (value.kind_of? Range)
first_value = convert_to_lucene(value.first)
last_value = convert_to_lucene(value.last)
first = org.apache.lucene.index.Term.new(key.to_s, first_value)
last = org.apache.lucene.index.Term.new(key.to_s, last_value)
first = org.apache.lucene.index.Term.new(key.to_s, first_value)
last = org.apache.lucene.index.Term.new(key.to_s, last_value)
$LUCENE_LOGGER.debug{"convert_to_query: Range key '#{key.to_s}' #{first_value}' to '#{last_value}'"}
org.apache.lucene.search.RangeQuery.new(first, last, !value.exclude_end?)
elsif
converted_value = convert_to_lucene(value)
term = org.apache.lucene.index.Term.new(key.to_s, converted_value)
term = org.apache.lucene.index.Term.new(key.to_s, converted_value)
org.apache.lucene.search.TermQuery.new(term)
# pq = org.apache.lucene.search.PhraseQuery.new
# pq.add(term)
# pq.setSlop 3
# pq
# pq = org.apache.lucene.search.PhraseQuery.new
# pq.add(term)
# pq.setSlop 3
# pq
end
end

Expand All @@ -95,9 +108,8 @@ def ==(other)
end

def to_s
s = "FieldInfo(#{self.object_id.to_s})
@info.each_pair {|key,value| s << "#{key}=#{value} "}
s + "]"
infos = @info.keys.inject(""){|s, key| s << "#{key}=#{@info[key]} "}
"FieldInfo(#{self.object_id.to_s}) [#{infos}]"
end


Expand Down
20 changes: 20 additions & 0 deletions lib/neo4j/mixins/node.rb
Expand Up @@ -324,6 +324,26 @@ def fire_event(event)

# ------------------------------------------------------------------------


def property(*props)
pname = props[0].to_sym
if props.size > 1
properties_info[pname] = *props[1..-1]
else
properties_info[pname] = {}
end

define_method(pname) do
get_property(pname.to_s)
end

name = (pname.to_s() +"=").to_sym
define_method(name) do |value|
set_property(pname.to_s, value)
end
end


#
# Declares Neo4j node properties.
# You need to declare properties in order to set them unless you include the Neo4j::DynamicAccessorMixin mixin.
Expand Down
6 changes: 3 additions & 3 deletions neo4j.gemspec
@@ -1,5 +1,5 @@
# WARNING : RAKE AUTO-GENERATED FILE. DO NOT MANUALLY EDIT!
# LAST UPDATED : Tue Dec 09 19:10:33 +0100 2008
# LAST UPDATED : Wed Dec 10 15:30:46 +0100 2008
#
# RUN : 'rake gem:update_gemspec'

Expand Down Expand Up @@ -38,7 +38,6 @@ Gem::Specification.new do |s|
"lib/neo4j/neo.rb",
"lib/neo4j/transaction.rb",
"lib/neo4j/relations",
"lib/neo4j/value_object.rb",
"lib/neo4j/mixins/transactional.rb",
"lib/neo4j/mixins/node.rb",
"lib/neo4j/mixins/relation.rb",
Expand Down Expand Up @@ -70,6 +69,7 @@ Gem::Specification.new do |s|
"test/neo4j/node_spec.rb",
"test/neo4j/relation_spec.rb",
"test/neo4j/value_object_spec.rb",
"test/neo4j/ref_node_spec.rb",
"test/neo4j/person_spec.rb",
"examples/imdb",
"examples/imdb/install.sh",
Expand All @@ -80,7 +80,7 @@ Gem::Specification.new do |s|
"examples/imdb/load_test.rb"]
s.rubygems_version = "1.3.1"
s.platform = "ruby"
s.date = "Tue Dec 09 00:00:00 +0100 2008"
s.date = "Wed Dec 10 00:00:00 +0100 2008"
s.homepage = "http://github.com/andreasronge/neo4j/tree"
s.rubyforge_project = "neo4j"
s.bindir = "bin"
Expand Down
22 changes: 22 additions & 0 deletions test/lucene/field_info_spec.rb
Expand Up @@ -44,5 +44,27 @@
c.should == ["00000000001", "00000000002", "00000000003"]
end

it "should convert to correct ruby type from a lucene string value" do
f = FieldInfo.new
f[:type] = Fixnum
f.convert_to_ruby("123").should == 123
end

it "should convert Dates to lucene" do
f = FieldInfo.new
f[:type] = Date
f.convert_to_lucene(Date.new(2008,12,15)).should == "20081215"
end

it "should convert Dates from lucene" do
f = FieldInfo.new
f[:type] = Date
d = f.convert_to_ruby('20081215')
d.should be_instance_of(Date)
d.year.should == 2008
d.month.should == 12
d.day.should == 15
end

end

45 changes: 45 additions & 0 deletions test/lucene/index_spec.rb
Expand Up @@ -416,6 +416,27 @@
hits[0][:bar].should == 3.14
hits[0][:name].should == 'andreas'
end


it "can be used to convert and store Date properties" do
#given
@index.field_infos[:since][:store] = true
@index.field_infos[:since][:type] = Date

@index << {:id => 1, :since => Date.new(2008,3,26)}
@index.commit

# when
hits = @index.find(:id => "1")

# then
hits.size.should == 1
hits[0][:since].should be_instance_of(Date)
hits[0][:since].year.should == 2008
hits[0][:since].month.should == 3
hits[0][:since].day.should == 26
end

end

describe Index, " when updating a document" do
Expand Down Expand Up @@ -462,5 +483,29 @@
res.size.should == 2
end


describe "Indexing with Dates" do
before(:each) do
setup_lucene
@index = Index.new('myindex')
@index.field_infos[:since][:store] = false
@index.field_infos[:since][:type] = Date
end


it "can find an index using a date" do
#given

@index << {:id => 1, :since => Date.new(2008,4,26)}
@index.commit

# when
hits = @index.find(:since => Date.new(2008,4,26))

# then
hits.size.should == 1
hits[0][:id].should == '1'
end
end
end

8 changes: 4 additions & 4 deletions test/neo4j/node_spec.rb
Expand Up @@ -89,13 +89,13 @@ class TestNode
end

ref_node = Neo4j.instance.ref_node
ref_node.relations.outgoing(TestNode.to_s).should be_empty
ref_node.relations.outgoing(TestNode).should be_empty

# when
t = TestNode.new

# then
nodes = ref_node.relations.outgoing(TestNode.to_s).nodes
nodes = ref_node.relations.outgoing(TestNode).nodes
nodes.to_a.size.should == 1
nodes.should include(t)
end
Expand All @@ -109,13 +109,13 @@ class SubNode < TestNode
end

ref_node = Neo4j.instance.ref_node
ref_node.relations.outgoing(TestNode.to_s).should be_empty
ref_node.relations.outgoing(TestNode).should be_empty

# when
t = SubNode.new

# then
nodes = ref_node.relations.outgoing(TestNode.to_s).nodes
nodes = ref_node.relations.outgoing(TestNode).nodes
nodes.to_a.size.should == 1
nodes.should include(t)
SubNode.root_class.should == TestNode.to_s
Expand Down
12 changes: 6 additions & 6 deletions test/neo4j/value_object_spec.rb
Expand Up @@ -6,9 +6,9 @@



undefine_class :MyNode
undefine_class :FooBarNode

class MyNode
class FooBarNode
include Neo4j::NodeMixin
properties :name, :age
end
Expand All @@ -20,13 +20,13 @@ class MyNode


it "should value object created with new param should be anew record" do
clazz = MyNode.value_object
clazz = FooBarNode.value_object
a = clazz.new
a.should be_new_record
end

it "update with correct values" do
clazz = MyNode.value_object
clazz = FooBarNode.value_object
a = clazz.new
a._update(:name => 'hej', :age=>42)
a.name.should == 'hej'
Expand All @@ -35,7 +35,7 @@ class MyNode
end

it "update with incorrect values" do
clazz = MyNode.value_object
clazz = FooBarNode.value_object
a = clazz.new
a._update(:ojoj => 'hej', :age=>42)
a.name.should == nil
Expand All @@ -44,7 +44,7 @@ class MyNode
end

it "create a value object from an existing node" do
node = MyNode.new
node = FooBarNode.new
node.name = 'hej'

vo = node.value_object
Expand Down

0 comments on commit 3ec34b1

Please sign in to comment.