Loading histream-core/src/main/java/de/sekmi/histream/inference/DependencyExpandingIterator.java 0 → 100644 +57 −0 Original line number Diff line number Diff line package de.sekmi.histream.inference; import java.util.Iterator; import java.util.NoSuchElementException; public class DependencyExpandingIterator implements Iterator<String> { private InferenceFactory factory; private Iterator<String> concepts; /** Temporary iterator for dependencies */ private Iterator<String> temp; private String next; public DependencyExpandingIterator(InferenceFactory factory, Iterator<String> concepts) { this.concepts = concepts; this.factory = factory; } @Override public boolean hasNext() { prefetch(); return null != next; } private void prefetch(){ while( next == null ){ if( temp != null && temp.hasNext() ){ // fetch next dependency next = temp.next(); }else if( concepts.hasNext() ){ next = concepts.next(); // try whether this concept is inferred InferredConcept ic = factory.getConceptById(next); if( ic == null ){ // can not infer this concept, leave as is }else{ // can infer this concept // remove the concept id and replace with dependency IDs next = null; temp = ic.getDependencyIDs(); // continue, fetch first dependency in next iteration } }else{ // no more concepts break; } } } @Override public String next() { prefetch(); if( next != null ){ throw new NoSuchElementException(); } return next; } } histream-core/src/main/java/de/sekmi/histream/inference/EncounterInferenceFactory.java +2 −14 Original line number Diff line number Diff line package de.sekmi.histream.inference; import de.sekmi.histream.ObservationFactory; public interface EncounterInferenceFactory { void setObservationFactory(ObservationFactory factory); /** * Determine whether this inference factory can infer * facts with the given concept id. * * @param inferredConceptId inferred concept * @return true if the concept can be inferred, false otherwise. */ boolean canInfer(String inferredConceptId); public abstract class EncounterInferenceFactory extends InferenceFactory { /** * Create an inference engine which infers the given concept id. Loading @@ -20,5 +8,5 @@ public interface EncounterInferenceFactory { * @return inference engine or {@code null} if the concept is not * supported by this factory. */ public EncounterInferenceEngine createEngine(String inferredConceptId); public abstract EncounterInferenceEngine createEngine(String inferredConceptId); } histream-core/src/main/java/de/sekmi/histream/inference/InferenceFactory.java 0 → 100644 +42 −0 Original line number Diff line number Diff line package de.sekmi.histream.inference; import java.util.Iterator; import de.sekmi.histream.ObservationFactory; public abstract class InferenceFactory { protected ObservationFactory factory; public void setObservationFactory(ObservationFactory factory){ this.factory = factory; } /** * Determine whether this inference factory can infer * facts with the given concept id. * * @param inferredConceptId inferred concept * @return true if the concept can be inferred, false otherwise. */ public abstract boolean canInfer(String inferredConceptId); public abstract InferredConcept getConceptById(String inferredConceptId); /** * Expand a list of concept IDs with dependencies of corresponding * inferred concepts. * <p> * If a concept can be inferred by this inference factory, it is * replaced with its dependencies. Other concept IDs are not modified. * </p> * <p> * This is mainly useful for generating a list of concept ids for * a database query. * </p> * @param concepts * @return iterator of concepts which replaces inferred concepts * with their corresponding dependencies. */ public Iterator<String> expandConceptDependencies(Iterator<String> concepts){ return new DependencyExpandingIterator(this, concepts); } } histream-core/src/main/java/de/sekmi/histream/inference/InferredConcept.java +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import java.util.Iterator; public interface InferredConcept { // TODO need producing of multiple concepts? public String getConceptId(); public Iterator<String> getDependencyIDs(); Loading histream-js/src/main/java/de/sekmi/histream/scripting/JSEncounterInferenceFactory.java +73 −24 Original line number Diff line number Diff line Loading @@ -5,50 +5,85 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.nio.CharBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import de.sekmi.histream.ObservationFactory; import de.sekmi.histream.inference.EncounterInferenceEngine; import de.sekmi.histream.inference.EncounterInferenceFactory; import de.sekmi.histream.inference.InferredConcept; import jdk.nashorn.api.scripting.ScriptObjectMirror; public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ public class JSEncounterInferenceFactory extends EncounterInferenceFactory{ private ScriptEngineManager sem; private ObservationFactory os; private List<Script> scripts; private Map<String, InferenceEntry> inferenceLookup; public JSEncounterInferenceFactory() { sem = new ScriptEngineManager(); this.scripts = new ArrayList<>(); this.inferenceLookup = new HashMap<>(); } private static class Script{ URL location; String charset; String script; String[] produces; String[] requires; public Script(URL location, String charset){ this.location = location; this.charset = charset; public Script(String script){ this.script = script; } } private static class InferenceEntry implements InferredConcept{ private Script script; private int conceptIndex; public InferenceEntry(Script script, int conceptIndex){ this.script = script; this.conceptIndex = conceptIndex; } @Override public Iterator<String> getDependencyIDs() { return Arrays.stream(script.produces).iterator(); } @Override public String getConceptId() { return script.produces[conceptIndex]; } } private String readReader(Reader reader) throws IOException{ StringBuilder builder = new StringBuilder(); CharBuffer buffer = CharBuffer.allocate(2048); while( reader.read(buffer) != -1 ){ buffer.flip(); builder.append(buffer.toString()); buffer.clear(); } return builder.toString(); } public void addScript(URL scriptLocation, String charsetName) throws IOException, ScriptException{ ScriptEngine meta = sem.getEngineByName("nashorn"); // TODO use script context for control of error writer and bindings Bindings bindings = meta.createBindings(); String source; try( InputStream in = scriptLocation.openStream(); Reader reader = new InputStreamReader(in, charsetName) Reader reader = new InputStreamReader(in, charsetName); ){ meta.eval(reader, bindings); source = readReader(reader); meta.eval(source, bindings); } Script script = new Script(scriptLocation, charsetName); Script script = new Script(source); // retrieve metadata Object p = bindings.get("produces"); if( p == null ){ Loading @@ -73,24 +108,33 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ }else{ throw new ScriptException("Unable to read this.requires of type "+p.getClass(), scriptLocation.toString(), -1); } scripts.add(script); } @Override public void setObservationFactory(ObservationFactory factory) { this.os = factory; addScript(script); } @Override public boolean canInfer(String inferredConceptId) { // TODO use hashmap for more efficient lookups for( Script s : scripts ){ for( String prod : s.produces ){ if( prod.equals(inferredConceptId) ){ return true; private void addScript(Script script){ // verify that the produced concept ids are unique to this factory for( String id : script.produces ){ if( inferenceLookup.containsKey(id) ){ throw new IllegalStateException("Produced concept id '"+id+"' not unique to inference engine"); } } for( int i=0; i<script.produces.length; i++ ){ inferenceLookup.put(script.produces[i], new InferenceEntry(script,i)); } scripts.add(script); } private Script getScript(String inferredConceptId){ InferenceEntry e = inferenceLookup.get(inferredConceptId); if( e == null ){ return null; }else{ return e.script; } } return false; @Override public boolean canInfer(String inferredConceptId) { return inferenceLookup.containsKey(inferredConceptId); } @Override Loading @@ -99,4 +143,9 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ return null; } @Override public InferredConcept getConceptById(String inferredConceptId) { return inferenceLookup.get(inferredConceptId); } } Loading
histream-core/src/main/java/de/sekmi/histream/inference/DependencyExpandingIterator.java 0 → 100644 +57 −0 Original line number Diff line number Diff line package de.sekmi.histream.inference; import java.util.Iterator; import java.util.NoSuchElementException; public class DependencyExpandingIterator implements Iterator<String> { private InferenceFactory factory; private Iterator<String> concepts; /** Temporary iterator for dependencies */ private Iterator<String> temp; private String next; public DependencyExpandingIterator(InferenceFactory factory, Iterator<String> concepts) { this.concepts = concepts; this.factory = factory; } @Override public boolean hasNext() { prefetch(); return null != next; } private void prefetch(){ while( next == null ){ if( temp != null && temp.hasNext() ){ // fetch next dependency next = temp.next(); }else if( concepts.hasNext() ){ next = concepts.next(); // try whether this concept is inferred InferredConcept ic = factory.getConceptById(next); if( ic == null ){ // can not infer this concept, leave as is }else{ // can infer this concept // remove the concept id and replace with dependency IDs next = null; temp = ic.getDependencyIDs(); // continue, fetch first dependency in next iteration } }else{ // no more concepts break; } } } @Override public String next() { prefetch(); if( next != null ){ throw new NoSuchElementException(); } return next; } }
histream-core/src/main/java/de/sekmi/histream/inference/EncounterInferenceFactory.java +2 −14 Original line number Diff line number Diff line package de.sekmi.histream.inference; import de.sekmi.histream.ObservationFactory; public interface EncounterInferenceFactory { void setObservationFactory(ObservationFactory factory); /** * Determine whether this inference factory can infer * facts with the given concept id. * * @param inferredConceptId inferred concept * @return true if the concept can be inferred, false otherwise. */ boolean canInfer(String inferredConceptId); public abstract class EncounterInferenceFactory extends InferenceFactory { /** * Create an inference engine which infers the given concept id. Loading @@ -20,5 +8,5 @@ public interface EncounterInferenceFactory { * @return inference engine or {@code null} if the concept is not * supported by this factory. */ public EncounterInferenceEngine createEngine(String inferredConceptId); public abstract EncounterInferenceEngine createEngine(String inferredConceptId); }
histream-core/src/main/java/de/sekmi/histream/inference/InferenceFactory.java 0 → 100644 +42 −0 Original line number Diff line number Diff line package de.sekmi.histream.inference; import java.util.Iterator; import de.sekmi.histream.ObservationFactory; public abstract class InferenceFactory { protected ObservationFactory factory; public void setObservationFactory(ObservationFactory factory){ this.factory = factory; } /** * Determine whether this inference factory can infer * facts with the given concept id. * * @param inferredConceptId inferred concept * @return true if the concept can be inferred, false otherwise. */ public abstract boolean canInfer(String inferredConceptId); public abstract InferredConcept getConceptById(String inferredConceptId); /** * Expand a list of concept IDs with dependencies of corresponding * inferred concepts. * <p> * If a concept can be inferred by this inference factory, it is * replaced with its dependencies. Other concept IDs are not modified. * </p> * <p> * This is mainly useful for generating a list of concept ids for * a database query. * </p> * @param concepts * @return iterator of concepts which replaces inferred concepts * with their corresponding dependencies. */ public Iterator<String> expandConceptDependencies(Iterator<String> concepts){ return new DependencyExpandingIterator(this, concepts); } }
histream-core/src/main/java/de/sekmi/histream/inference/InferredConcept.java +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import java.util.Iterator; public interface InferredConcept { // TODO need producing of multiple concepts? public String getConceptId(); public Iterator<String> getDependencyIDs(); Loading
histream-js/src/main/java/de/sekmi/histream/scripting/JSEncounterInferenceFactory.java +73 −24 Original line number Diff line number Diff line Loading @@ -5,50 +5,85 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.nio.CharBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import de.sekmi.histream.ObservationFactory; import de.sekmi.histream.inference.EncounterInferenceEngine; import de.sekmi.histream.inference.EncounterInferenceFactory; import de.sekmi.histream.inference.InferredConcept; import jdk.nashorn.api.scripting.ScriptObjectMirror; public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ public class JSEncounterInferenceFactory extends EncounterInferenceFactory{ private ScriptEngineManager sem; private ObservationFactory os; private List<Script> scripts; private Map<String, InferenceEntry> inferenceLookup; public JSEncounterInferenceFactory() { sem = new ScriptEngineManager(); this.scripts = new ArrayList<>(); this.inferenceLookup = new HashMap<>(); } private static class Script{ URL location; String charset; String script; String[] produces; String[] requires; public Script(URL location, String charset){ this.location = location; this.charset = charset; public Script(String script){ this.script = script; } } private static class InferenceEntry implements InferredConcept{ private Script script; private int conceptIndex; public InferenceEntry(Script script, int conceptIndex){ this.script = script; this.conceptIndex = conceptIndex; } @Override public Iterator<String> getDependencyIDs() { return Arrays.stream(script.produces).iterator(); } @Override public String getConceptId() { return script.produces[conceptIndex]; } } private String readReader(Reader reader) throws IOException{ StringBuilder builder = new StringBuilder(); CharBuffer buffer = CharBuffer.allocate(2048); while( reader.read(buffer) != -1 ){ buffer.flip(); builder.append(buffer.toString()); buffer.clear(); } return builder.toString(); } public void addScript(URL scriptLocation, String charsetName) throws IOException, ScriptException{ ScriptEngine meta = sem.getEngineByName("nashorn"); // TODO use script context for control of error writer and bindings Bindings bindings = meta.createBindings(); String source; try( InputStream in = scriptLocation.openStream(); Reader reader = new InputStreamReader(in, charsetName) Reader reader = new InputStreamReader(in, charsetName); ){ meta.eval(reader, bindings); source = readReader(reader); meta.eval(source, bindings); } Script script = new Script(scriptLocation, charsetName); Script script = new Script(source); // retrieve metadata Object p = bindings.get("produces"); if( p == null ){ Loading @@ -73,24 +108,33 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ }else{ throw new ScriptException("Unable to read this.requires of type "+p.getClass(), scriptLocation.toString(), -1); } scripts.add(script); } @Override public void setObservationFactory(ObservationFactory factory) { this.os = factory; addScript(script); } @Override public boolean canInfer(String inferredConceptId) { // TODO use hashmap for more efficient lookups for( Script s : scripts ){ for( String prod : s.produces ){ if( prod.equals(inferredConceptId) ){ return true; private void addScript(Script script){ // verify that the produced concept ids are unique to this factory for( String id : script.produces ){ if( inferenceLookup.containsKey(id) ){ throw new IllegalStateException("Produced concept id '"+id+"' not unique to inference engine"); } } for( int i=0; i<script.produces.length; i++ ){ inferenceLookup.put(script.produces[i], new InferenceEntry(script,i)); } scripts.add(script); } private Script getScript(String inferredConceptId){ InferenceEntry e = inferenceLookup.get(inferredConceptId); if( e == null ){ return null; }else{ return e.script; } } return false; @Override public boolean canInfer(String inferredConceptId) { return inferenceLookup.containsKey(inferredConceptId); } @Override Loading @@ -99,4 +143,9 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{ return null; } @Override public InferredConcept getConceptById(String inferredConceptId) { return inferenceLookup.get(inferredConceptId); } }