Neo4j doesn't provide the functionality you're asking for out of the box, but since you've already come as far as correctly populating your database, the traversal that you need is just a few lines of code.
I've recreated your experiment here, with a few modifications. First of all, I populate the database with a single pass through the text (steps 2 and 3), but that's a minor. More importantly, I only store the number of occurrences on each relationship and the total number on the node (step 4), as I don't think there is a need to pre-calculate probabilities.
The code that you're asking for then looks something like this:
/**
* A component that creates a random sentence by a random walk on a Markov Chain stored in Neo4j, produced by
* {@link NGramDatabasePopulator}.
*/
public class RandomSentenceCreator {
private final Random random = new Random(System.currentTimeMillis());
/**
* Create a random sentence from the underlying n-gram model. Starts at a random node an follows random outgoing
* relationships of type {@link Constants#REL} with a probability proportional to that transition occurrence in the
* text that was processed to form the model. This happens until the desired length is achieved. In case a node with
* no outgoing relationships it reached, the walk is re-started from a random node.
*
* @param database storing the n-gram model.
* @param length desired number of characters in the random sentence.
* @return random sentence.
*/
public String createRandomSentence(GraphDatabaseService database, int length) {
Node startNode = randomNode(database);
return walk(startNode, length, 0);
}
private String walk(Node startNode, int maxLength, int currentLength) {
if (currentLength >= maxLength) {
return (String) startNode.getProperty(NAME);
}
int totalRelationships = (int) startNode.getProperty(TOTAL, 0);
if (totalRelationships == 0) {
//terminal node, restart from random
return walk(randomNode(startNode.getGraphDatabase()), maxLength, currentLength);
}
int choice = random.nextInt(totalRelationships) + 1;
int total = 0;
Iterator<Relationship> relationshipIterator = startNode.getRelationships(OUTGOING, REL).iterator();
Relationship toFollow = null;
while (total < choice && relationshipIterator.hasNext()) {
toFollow = relationshipIterator.next();
total += (int) toFollow.getProperty(PROBABILITY);
}
Node nextNode;
if (toFollow == null) {
//no relationship to follow => stay on the same node and try again
nextNode = startNode;
} else {
nextNode = toFollow.getEndNode();
}
return ((String) nextNode.getProperty(NAME)).substring(0, 1) + walk(nextNode, maxLength, currentLength + 1);
}
private Node randomNode(GraphDatabaseService database) {
return random(GlobalGraphOperations.at(database).getAllNodes());
}
}