use of apoc.result.MapResult in project neo4j-apoc-procedures by neo4j-contrib.
the class Cypher method whenCase.
@Procedure("apoc.case")
@Description("apoc.case([condition, query, condition, query, ...], elseQuery:'', params:{}) yield value - given a list of conditional / read-only query pairs, executes the query associated with the first conditional evaluating to true (or the else query if none are true) with the given parameters")
public Stream<MapResult> whenCase(@Name("conditionals") List<Object> conditionals, @Name(value = "elseQuery", defaultValue = "") String elseQuery, @Name(value = "params", defaultValue = "") Map<String, Object> params) {
if (params == null)
params = Collections.emptyMap();
if (conditionals.size() % 2 != 0) {
throw new IllegalArgumentException("Conditionals must be an even-sized collection of boolean, query entries");
}
Iterator caseItr = conditionals.iterator();
while (caseItr.hasNext()) {
boolean condition = (Boolean) caseItr.next();
String ifQuery = (String) caseItr.next();
if (condition) {
return db.execute(withParamMapping(ifQuery, params.keySet()), params).stream().map(MapResult::new);
}
}
if (elseQuery.isEmpty()) {
return Stream.of(new MapResult(Collections.emptyMap()));
} else {
return db.execute(withParamMapping(elseQuery, params.keySet()), params).stream().map(MapResult::new);
}
}
use of apoc.result.MapResult in project neo4j-apoc-procedures by neo4j-contrib.
the class Cypher method mapParallel2.
@Procedure
@Description("apoc.cypher.mapParallel2(fragment, params, list-to-parallelize) yield value - executes fragment in parallel batches with the list segments being assigned to _")
public Stream<MapResult> mapParallel2(@Name("fragment") String fragment, @Name("params") Map<String, Object> params, @Name("list") List<Object> data, @Name("partitions") long partitions) {
final String statement = withParamsAndIterator(fragment, params.keySet(), "_");
db.execute("EXPLAIN " + statement).close();
BlockingQueue<RowResult> queue = new ArrayBlockingQueue<>(100000);
Stream<List<Object>> parallelPartitions = Util.partitionSubList(data, (int) (partitions <= 0 ? PARTITIONS : partitions), null);
Util.inFuture(() -> {
long total = parallelPartitions.map((List<Object> partition) -> {
try {
return executeStatement(queue, statement, parallelParams(params, "_", partition), false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}).count();
queue.put(RowResult.TOMBSTONE);
return total;
});
return StreamSupport.stream(new QueueBasedSpliterator<>(queue, RowResult.TOMBSTONE, terminationGuard), true).map((rowResult) -> new MapResult(rowResult.result));
}
use of apoc.result.MapResult in project neo4j-apoc-procedures by neo4j-contrib.
the class Timeboxed method runTimeboxed.
@Procedure
@Description("apoc.cypher.runTimeboxed('cypherStatement',{params}, timeout) - abort statement after timeout ms if not finished")
public Stream<MapResult> runTimeboxed(@Name("cypher") String cypher, @Name("params") Map<String, Object> params, @Name("timeout") long timeout) {
final BlockingQueue<Map<String, Object>> queue = new ArrayBlockingQueue<>(100);
final AtomicReference<Transaction> txAtomic = new AtomicReference<>();
// run query to be timeboxed in a separate thread to enable proper tx termination
// if we'd run this in current thread, a tx.terminate would kill the transaction the procedure call uses itself.
Pools.DEFAULT.submit(() -> {
try (Transaction tx = db.beginTx()) {
txAtomic.set(tx);
Result result = db.execute(cypher, params == null ? Collections.EMPTY_MAP : params);
while (result.hasNext()) {
final Map<String, Object> map = result.next();
offerToQueue(queue, map, timeout);
}
offerToQueue(queue, POISON, timeout);
tx.success();
} catch (TransactionTerminatedException e) {
log.warn("query " + cypher + " has been terminated");
} finally {
txAtomic.set(null);
}
});
//
Pools.SCHEDULED.schedule(() -> {
Transaction tx = txAtomic.get();
if (tx == null) {
log.info("tx is null, either the other transaction finished gracefully or has not yet been start.");
} else {
tx.terminate();
offerToQueue(queue, POISON, timeout);
log.warn("terminating transaction, putting POISON onto queue");
}
}, timeout, MILLISECONDS);
// consume the blocking queue using a custom iterator finishing upon POISON
Iterator<Map<String, Object>> queueConsumer = new Iterator<Map<String, Object>>() {
Map<String, Object> nextElement = null;
boolean hasFinished = false;
@Override
public boolean hasNext() {
if (hasFinished) {
return false;
} else {
try {
nextElement = queue.poll(timeout, MILLISECONDS);
if (nextElement == null) {
log.warn("couldn't grab queue element, aborting - this should never happen");
hasFinished = true;
} else {
hasFinished = POISON.equals(nextElement);
}
return !hasFinished;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public Map<String, Object> next() {
return nextElement;
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(queueConsumer, Spliterator.ORDERED), false).map(MapResult::new);
}
Aggregations