Sorry to beat on this old horse again, but I just thought I'd share another
solution: using the graph matching component (in Java, but you could
probably translate it quite easily to Scala):
public class VisibleMessagesByFollowedUsers implements Iterable<Node>
{
private final PatternNode start = new PatternNode();
private final PatternNode message = new PatternNode();
private final Node startNode;
public VisibleMessagesByFollowedUsers( Node startNode )
{
this.startNode = startNode;
if ( !STATIC_PATTERN ) start.setAssociation( startNode );
PatternNode user = new PatternNode();
start.createRelationshipTo( user, withName( "FOLLOWS" ) );
user.createRelationshipTo( message, withName( "CREATED" ) );
message.createRelationshipTo( start, withName( "IS_VISIBLE_BY" )
);
}
public Iterator<Node> iterator()
{
Iterable<PatternMatch> matches =
PatternMatcher.getMatcher().match(
start, startNode );
return new IteratorWrapper<Node, PatternMatch>(
matches.iterator() )
{
@Override
protected Node underlyingObjectToObject( PatternMatch match
)
{
return match.getNodeFor( message );
}
};
}
}
This code would then be used like so:
for ( Node message : new VisibleMessagesByFollowedUsers(
userNodeToGetMessagesFor ) )
{
displayMessageToUser( message );
}
Happy Hacking!
- Tobias
On Wed, Mar 17, 2010 at 12:06 PM, Craig Taverner <[email protected]> wrote:
> I'm uncertain about one ambiguity in your model, you are able to find
> messages through FOLLOWS and IS_VISIBLE_BY. These will give two different
> sets, and my first impression was that FOLLOWS gives you the right answer.
> In other words you want to query for 'all messages by users I follow'? In
> that case you do not need IS_VISIBLE_BY. However, if there are messages by
> people you follow, but are not allowed to see, then you also need the
> IS_VISIBLE_BY. But I would still reconsider linking directly from the
> viewer
> to the message for that case. I'd rather have the messages linked to some
> categorization structure for things like 'public', 'private', etc.
>
> Anyway, here are some suggestions for the various approaches above:
> *'all messages by users I follow'*
> val msgs = viewer.traverse(
> Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH,
> (tp: TraversalPosition) => IsMessage(tp.currentNode()),
> Rels.FOLLOWS, Direction.OUTGOING,
> Rels.CREATED, Direction.OUTGOING)
>
> *'all messages visible to me'*
> val msgs = viewer.traverse(
> Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH,
> ReturnableEvaluator.ALL_BUT_START_NODE,
> Rels.IS_VISIBLE_BY, Direction.INCOMING)
>
> *'all messages, visible to me, by people I follow'*
> val msgs = viewer.traverse(
> Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH,
> (tp: TraversalPosition) => {
> val msg = tp.currentNode()
> IsMessage(msg) && IsVisibleBy(msg,viewer)
> },
> Rels.FOLLOWS, Direction.OUTGOING,
> Rels.CREATED, Direction.OUTGOING)
>
> Of course I assume you make the utility functions IsMessage(node: Node) and
> IsVisibleBy(msg: Node, user: Node), and these will test the existance of
> properties and relations as appropriate to make the decision.
>
>
> On Wed, Mar 17, 2010 at 6:32 AM, Lincoln <[email protected]> wrote:
>
> > Hi, I've just started looking at Neo4j and I'm quite intrigued. However,
> > the cognitive dissonance that I've grown so used to in modeling storage
> is
> > proving to be a bit difficult to let go at this early stage :)
> >
> > I was hoping that if someone could help me through an example I would be
> > able to grok how to properly structure my data and query it in Neo4j.
> >
> > Nodes:
> > Message( text: String )
> > User( id: Long )
> >
> > Relationships:
> > CREATED
> > FOLLOWS
> > IS_VISIBLE_BY
> >
> > So I might have a graph with entries like so:
> >
> > User(1) --> CREATED --> Message("i woke up late today")
> > User(2) --> CREATED --> Message("hello")
> > User(3) --> CREATED --> Message("ugh, i hate mondays")
> >
> > User(1) --> FOLLOWS --> User(2)
> >
> > Let's also say all messages are visible to User 1.
> >
> > Message("i woke up late today") --> IS_VISIBLE_BY --> User(1)
> > Message("hello") --> IS_VISIBLE_BY --> User(1)
> > Message("ugh, i hate mondays") --> IS_VISIBLE_BY --> User(1)
> >
> > So, I can do a simple traversal for visible:
> >
> > val graphDb = new EmbeddedGraphDatabase( "path/to/neo4j-db" )
> > val index = new LuceneIndexService( graphDb )
> > val viewer = index.getSingleNode("id", 1)
> > val msgs = viewer.traverse( Order.BREADTH_FIRST,
> > StopEvaluator.END_OF_GRAPH,
> > ReturnableEvaluator.ALL_BUT_START_NODE, Rels.IS_VISIBLE_BY,
> > Direction.INCOMING)
> > msgs.toList.map(_.toJson).mkString("{ msgs : [", ",", "] }") // assuming
> i
> > have the relevant functions
> >
> > But let's say that this is going to return too many messages. Just
> because
> > all the messages are possibly visible to me, doesn't mean I want to see
> > them
> > all. So, I'd like to additionally filter by the FOLLOWS relationship.
> I'd
> > like to express "get all messages that are visible and were created by a
> > user that I follow." Can someone show me an example of how to do that?
> >
> > I'm guessing that you need to implement a custom ReturnableEvaluator, but
> I
> > don't understand how you traverse multiple relationships at the same
> time.
> >
> > Thanks,
> > Lincoln
> > _______________________________________________
> > Neo mailing list
> > [email protected]
> > https://lists.neo4j.org/mailman/listinfo/user
> >
> _______________________________________________
> Neo mailing list
> [email protected]
> https://lists.neo4j.org/mailman/listinfo/user
>
--
Tobias Ivarsson <[email protected]>
Hacker, Neo Technology
www.neotechnology.com
Cellphone: +46 706 534857
_______________________________________________
Neo mailing list
[email protected]
https://lists.neo4j.org/mailman/listinfo/user