On Sun, May 4, 2008 at 6:48 PM, Philip Jägenstedt <[EMAIL PROTECTED]> wrote:
> Now that I've finally gotten around to adding this index, l have some 
> questions.
>
>  First, it seems like IndexService and Index are used interchangably in
>  your reply. IndexService doesn't have a getSingleNodeFor so it seems a
>  getSingleNode with some constant key is what should be used. Is this
>  correct?

This is correct. I messed up the name of the getSingleNode() method.
You should use IndexService and IndexService alone. An IndexService
can maintain multiple indexes (typically one per property key) whereas
the old Index only represents one particular index structure (~= for
one particular key). So write all your stuff against the IndexService
interface -- except of course the one place in your code when you "new
up" the particular IndexService implementation of your choice (e.g.
LuceneIndexService or NeoIndexService). This is done once, typically
in application initialization code.

>
>  Second, in my case the index can't be done in the artist factory as
>  the id is not know at that time. This would be the case for any
>  optional attribute. Instead it is created in the setId method on the
>  Artist class. This must be a very common scenario and I suppose that
>  you've all though of good design patterns for this.
>  (http://wiki.neo4j.org/content/Advanced_Design_Guide seems completely
>  outdated so I'm ignoring that.) Basically I don't want to sprinkle
>  "new NeoIndexService(neo)" throughout my code, but my puny Java brain
>  has thought all afternoon without figuring out something that fits
>  nicely with the niceness of http://wiki.neo4j.org/content/Design_Guide

It seems weird to me that an attribute named "id" would be optional,
but anywho, I get your point. Unfortunately, there's currently no way
you can get around having to manually let the IndexService know that
an indexed property has changed. In the future, we're going to enable
hooking an IndexService into the event framework and then
declaratively specify property keys that it should watch and reindex.

But for now, you're going to have to notify the IndexService (via the
index() method) that an attribute has changed. This shouldn't be too
invasive in your code, of course, since you probably don't index on a
lot of attributes and you hopefully mutate those few attributes in a
single, well-defined place. In your case it's probably just going to
affect the setId() method, right?

You wouldn't sprinkle "new NeoIndexService(neo)" in there though, as
you wrote in your mail. Rather than instantiating a bunch of indexes,
you'd get a reference to the one instance of IndexService that you've
initialized in your app startup code.

How do you get access to this instance? Ah, dependency resolution.
Without theoretizing too much, there are roughly three ways you can go
about this:

   1. Access it through a singleton. This was the de-facto Right
Solution(tm) of the mid 90s, inspired by the GoF Design Patterns book
(p127). I.e. in a class, declare a "public static IndexService
getIndexService()" and statically invoke it from whenever you need an
IndexService, for example in your Arist.setId() method.

   2. Well, then after a while the software development community
decided that a) Singleton Was Broken for a component-oriented and
unit-tested world and b) that dependency injection (aka "inversion of
control") was the right way to go. Lots have been written about this
[1] but if you want to do it manually, you simply declare an
IndexService parameter in the constructor of every class where you
need to index stuff and then use that instance. For example:

--- >8 ---
public class Artist extends AbstractMusicBrainzEntity
{
   private final Node underlyingNode;
   private final IndexService indexService;

   public Artist( Node underlyingNode, IndexService indexService )
   {
      this.underlyingNode = underlyingNode;
      this.indexService = indexService;
   }

   public void setUuid( long uuid )
   {
      Transaction tx = neo.beginTx();
      try
      {
         underlyingNode.setProperty( PropertyKeys.UUID, uuid );
         indexService.indexService( underlyingNode, PropertyKeys.UUID, uuid );
         tx.success();
      }
      finally
      {
          tx.finish();
      }
   }
}
--- >8 ---

   3. Instead of manually wiring your components and entities
together, you could use a DI framework or container like Spring, or
PicoContainer or Guice. Actual syntax depends on the framework, but it
could look something like this:

--- >8 ---
public class Artist extends AbstractMusicBrainzEntity
{
   @Autowired
   private IndexService indexService;
   ...

   @Transactional
   public void setUuid( long uuid )
   {
      underlyingNode.setProperty( PropertyKeys.UUID, uuid );
      indexService.indexService( underlyingNode, PropertyKeys.UUID, uuid );
   }
}
--- >8 ---

1] This is probably not the best introduction today (it's really
showing signs of its age)... but the seminal article that coined the
term "depency injection" is by Martin Fowler here:
http://martinfowler.com/articles/injection.html.

Does that seem right to you?

>
>  What would Morpheus do?
>
>  Philip
>
>  BTW, a long[2] is just what is needed for indexing a UUID.

Hmm, it strikes me that our current indexes may not work correctly
with array values. Hashcode and equality on arrays are by default
based on the actual array *instance* in Java -- not on the underlying
elements in the array. So we would need to detect that someone is
passing in an array and then use Arrays.hashCode() and
Arrays.equals().

Johan -- is this how the current implementation works?

Cheers,

-- 
Emil Eifrém, CEO [EMAIL PROTECTED]
Neo Technology, www.neotechnology.com
Cell: +46 733 462 271 | US: 206 403 8808
_______________________________________________
Neo mailing list
User@lists.neo4j.org
https://lists.neo4j.org/mailman/listinfo/user

Reply via email to