com.thoughtworks.studios.journey.cspmining.SuffixTree.java Source code

Java tutorial

Introduction

Here is the source code for com.thoughtworks.studios.journey.cspmining.SuffixTree.java

Source

/**
 * This file is part of journey-neo4j-plugin. journey-neo4j-plugin is a neo4j server extension that provides out-of-box action path analysis features on top of the graph database.
 *
 * Copyright 2015 ThoughtWorks, Inc. and Pengchao Wang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.thoughtworks.studios.journey.cspmining;

import com.thoughtworks.studios.journey.models.Application;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.function.Function;
import org.neo4j.helpers.Predicate;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import static com.thoughtworks.studios.journey.utils.ArrayUtils.commonPrefix;
import static org.apache.commons.lang.ArrayUtils.subarray;
import static org.neo4j.helpers.collection.Iterables.*;

public class SuffixTree {
    public static final String TREE_NODE_LABEL = "SuffixTreeNode";
    private static final String TREE_ROOT_LABEL = "SuffixTreeRoot";
    private Application app;
    private TreeNode root;

    public static Iterable<SuffixTree> findByCategory(final Application app, final TreeCategory category) {
        Iterable<Node> rootNodes = app.getAllNodesWithLabel(TREE_ROOT_LABEL);

        Iterable<SuffixTree> allTrees = map(new Function<Node, SuffixTree>() {
            @Override
            public SuffixTree apply(Node rootNode) {
                return new SuffixTree(app, rootNode);
            }
        }, rootNodes);

        return filter(new Predicate<SuffixTree>() {
            @Override
            public boolean accept(SuffixTree tree) {
                return tree.getCategory().equals(category);
            }
        }, allTrees);
    }

    private TreeCategory getCategory() {
        return root.getTreeCategory();
    }

    public SuffixTree(Application app, Node rootNode) {
        this.app = app;
        this.root = new TreeNode(rootNode);
    }

    public SuffixTree(Application app, String rootAction, long supportBaseCount) {
        this.app = app;
        this.root = new TreeNode(this.app.graphDB().createNode(getLabel()));
        this.root.setNames(new String[] { rootAction });
        this.root.setSupportBaseCount(supportBaseCount);
    }

    public void setJourneysCount(long val) {
        this.root.setJourneyCount(val);
    }

    private Label getLabel() {
        return app.nameSpacedLabel(TREE_ROOT_LABEL);
    }

    public String getTreeName() {
        return this.root.getNames()[0];
    }

    public Iterable<TreeNode> depthFirstNodes(boolean orderedExpanding) {
        return root.depthFirstNodes(orderedExpanding);
    }

    public void addSuffix(List<String> suffix, long journeyId) {
        addSequenceWithNode(suffix.toArray(new String[suffix.size()]), root, journeyId);
    }

    private void addSequenceWithNode(String[] prefixNames, TreeNode currentNode, long journeyId) {
        if (prefixNames.length == 0) {
            return;
        }

        Iterable<TreeNode> children = currentNode.children();
        for (TreeNode child : children) {
            String[] childSequence = child.getNames();
            String[] sharedStartNames = commonPrefix(childSequence, prefixNames);

            if (sharedStartNames.length != 0) {
                if (sharedStartNames.length == childSequence.length) {
                    if (sharedStartNames.length == prefixNames.length) {
                        child.addJourneyId(journeyId);
                    } else {
                        addSequenceWithNode(trimSequence(prefixNames, sharedStartNames.length), child, journeyId);
                    }
                } else {
                    TreeNode commonNode = createChildNode(currentNode, sharedStartNames);
                    child.setNames(trimSequence(childSequence, sharedStartNames.length));
                    commonNode.addChild(child);
                    if (sharedStartNames.length == prefixNames.length) {
                        commonNode.addJourneyId(journeyId);
                    }
                    addSequenceWithNode(trimSequence(prefixNames, sharedStartNames.length), commonNode, journeyId);
                }
                return;
            }
        }

        TreeNode childNode = createChildNode(currentNode, prefixNames);
        childNode.addJourneyId(journeyId);
    }

    private String[] trimSequence(String[] originalSeq, int startIndex) {
        return (String[]) subarray(originalSeq, startIndex, originalSeq.length);
    }

    private TreeNode createChildNode(TreeNode parent, String[] names) {
        TreeNode child = new TreeNode(app.graphDB().createNode(app.nameSpacedLabel(TREE_NODE_LABEL)));
        child.setNames(names);
        parent.addChild(child);
        return child;
    }

    public void destroy() {
        root.delete();
    }

    public long getJourneyCount() {
        return root.getJourneyCount();
    }

    public long getSupportBase() {
        return root.getSupportBaseCount();
    }

    public void setCategory(TreeCategory treeCategory) {
        root.setTreeCategory(treeCategory);
    }

    public List<String> pathTo(TreeNode node) {
        List<String> path = new LinkedList<>();
        path.add(root.getNames()[0]);

        List<TreeNode> suffix = node.pathToRoot();

        for (TreeNode treeNode : reverse(suffix)) {
            Collections.addAll(path, treeNode.getNames());
        }
        return path;
    }

    public TreeNode getRoot() {
        return root;
    }
}