Java tutorial
/** * Copyright (C) 2014 The SciGraph authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.sdsc.scigraph.internal; import static com.google.common.base.Joiner.on; import static com.google.common.collect.Iterables.getFirst; import static com.google.common.collect.Sets.newHashSet; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrSubstitutor; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Result; import org.neo4j.graphdb.Transaction; import com.google.common.base.Splitter; import com.google.common.collect.Multimap; /*** * A utility for more expressive Cypher queries. * * <p> */ public class CypherUtil { private static final String ENTAILMENT_REGEX = "\\:[a-zA-Z0-9_:.|]*!"; private static Pattern pattern = Pattern.compile(ENTAILMENT_REGEX); private final GraphDatabaseService graphDb; @Inject public CypherUtil(GraphDatabaseService graphDb) { this.graphDb = graphDb; } /*** * @param query * @param params * @return */ public Result execute(String query, Multimap<String, Object> params) { query = substituteRelationships(query, params); query = entailRelationships(query); return graphDb.execute(query, flattenMap(params)); } static Map<String, Object> flattenMap(Multimap<String, Object> paramMap) { Map<String, Object> flatMap = new HashMap<>(); for (Entry<String, Collection<Object>> entry : paramMap.asMap().entrySet()) { flatMap.put(entry.getKey(), getFirst(entry.getValue(), null)); } return flatMap; } Set<String> getEntailedRelationshipTypes(Set<String> parents) { Set<String> entailedTypes = new HashSet<>(); for (String parent : parents) { entailedTypes.add(parent); Map<String, Object> params = new HashMap<>(); params.put("fragment", parent); try (Transaction tx = graphDb.beginTx()) { Result result = graphDb.execute("START parent=node:node_auto_index(fragment={fragment}) " + "MATCH (parent)<-[:subPropertyOf*]-(subProperty) " + "RETURN distinct subProperty.fragment as subProperty", params); while (result.hasNext()) { Map<String, Object> map = result.next(); entailedTypes.add((String) map.get("subProperty")); } tx.success(); } } return entailedTypes; } String entailRelationships(String cypher) { Matcher m = pattern.matcher(cypher); StringBuffer buffer = new StringBuffer(); while (m.find()) { String group = m.group().substring(1, m.group().length() - 1); Set<String> parentTypes = newHashSet(Splitter.on('|').split(group)); String entailedTypes = on('|').join(getEntailedRelationshipTypes(parentTypes)); m.appendReplacement(buffer, ":" + entailedTypes); } m.appendTail(buffer); return buffer.toString(); } static String substituteRelationships(String query, final Multimap<String, Object> valueMap) { StrSubstitutor substitutor = new StrSubstitutor(new StrLookup<String>() { @Override public String lookup(String key) { return on('|').join(valueMap.get(key)); } }); return substitutor.replace(query); } }