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