From f64ce5c5a06b307fe828ba2f3ceea7fda163a812 Mon Sep 17 00:00:00 2001 From: jenzur Date: Sun, 3 Mar 2019 13:17:07 +0100 Subject: [PATCH] updated calculations, updated handling calculation storages, updated DB retrieval, added Distance object, added levenstein, almost everything in mysqldatahandler, --- .../src/main/java/DataLayer/DataMapper.java | 43 ++ .../java/FunctionLayer/DistanceObject.java | 37 + .../FunctionLayer/LevenshteinDistance.java | 50 +- .../java/FunctionLayer/MYSQLDatahandler.java | 665 +++++++++--------- .../FunctionLayer/MessageResponseHandler.java | 5 +- .../StanfordParser/SentimentAnalyzerTest.java | 405 +++++------ .../PresentationLayer/DiscordHandler.java | 15 +- .../target/ArtificialAutism-1.0.jar | Bin 36247 -> 43185 bytes 8 files changed, 676 insertions(+), 544 deletions(-) create mode 100644 ArtificialAutism/src/main/java/FunctionLayer/DistanceObject.java diff --git a/ArtificialAutism/src/main/java/DataLayer/DataMapper.java b/ArtificialAutism/src/main/java/DataLayer/DataMapper.java index 4f41e8da..f1a0281f 100644 --- a/ArtificialAutism/src/main/java/DataLayer/DataMapper.java +++ b/ArtificialAutism/src/main/java/DataLayer/DataMapper.java @@ -14,6 +14,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -168,6 +169,47 @@ public class DataMapper { } } + public static LinkedHashMap> getAllRelationScores() { + int count = getSementicsDBRows(); + int counter2 = 0; + int hardCapRetrieveCount = 500000; + LinkedHashMap> LHMSMX = new LinkedHashMap(); + while (count > counter2) { + try (Connection l_cCon = DBCPDataSource.getConnection()) { + l_cCon.setAutoCommit(false); + String l_sSQL = "SELECT * FROM `WordMatrix` WHERE ID > " + counter2 + " AND ID < " + (counter2 + hardCapRetrieveCount); + try (PreparedStatement l_pStatement = l_cCon.prepareStatement(l_sSQL, java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY)) { + l_pStatement.setFetchSize(Integer.MIN_VALUE); + try (ResultSet l_rsSearch = l_pStatement.executeQuery()) { + int i = 0; + LinkedHashMap LHMLocal = new LinkedHashMap(); + while (l_rsSearch.next() && i < hardCapRetrieveCount) { + String str1 = l_rsSearch.getString(1); + String str2 = l_rsSearch.getString(2); + Double score = l_rsSearch.getDouble(3); + LHMLocal.put(str2, score); + while (l_rsSearch.next() && i < hardCapRetrieveCount && str1.equals(l_rsSearch.getString(1))) { + str2 = l_rsSearch.getString(2); + score = l_rsSearch.getDouble(3); + LHMLocal.put(str2, score); + i++; + counter2++; + } + LHMSMX.put(str1, LHMLocal); + System.out.println("i: " + i + "\n" + "free memory: " + Runtime.getRuntime().freeMemory() + "\ncounter2: " + counter2 + "\n"); + i++; + counter2++; + } + } + } + } catch (SQLException ex) { + Logger.getLogger(DataMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + return LHMSMX; + } + public static void CloseConnections(PreparedStatement ps, ResultSet rs, Connection con) { if (rs != null) { try { @@ -191,4 +233,5 @@ public class DataMapper { } } } + } diff --git a/ArtificialAutism/src/main/java/FunctionLayer/DistanceObject.java b/ArtificialAutism/src/main/java/FunctionLayer/DistanceObject.java new file mode 100644 index 00000000..a21282bc --- /dev/null +++ b/ArtificialAutism/src/main/java/FunctionLayer/DistanceObject.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package FunctionLayer; + +/** + * + * @author install1 + */ +public class DistanceObject { + + private Integer distance; + private String sentence; + + public DistanceObject() { + } + + public Integer getDistance() { + return distance; + } + + public void setDistance(Integer distance) { + this.distance = distance; + } + + public String getSentence() { + return sentence; + } + + + public DistanceObject(Integer distance, String sentence) { + this.distance = distance; + this.sentence = sentence; + } +} diff --git a/ArtificialAutism/src/main/java/FunctionLayer/LevenshteinDistance.java b/ArtificialAutism/src/main/java/FunctionLayer/LevenshteinDistance.java index 7632a4fe..4134e710 100644 --- a/ArtificialAutism/src/main/java/FunctionLayer/LevenshteinDistance.java +++ b/ArtificialAutism/src/main/java/FunctionLayer/LevenshteinDistance.java @@ -5,19 +5,35 @@ */ package FunctionLayer; +import java.util.concurrent.Callable; + /** * * @author install1 */ -public class LevenshteinDistance { +public class LevenshteinDistance implements Callable { + + private CharSequence lhs; + private CharSequence rhs; + private DistanceObject dco; private static int minimum(int a, int b, int c) { return Math.min(Math.min(a, b), c); } - public static int computeLevenshteinDistance(CharSequence lhs, CharSequence rhs) { - int[][] distance = new int[lhs.length() + 1][rhs.length() + 1]; + public LevenshteinDistance(CharSequence lhs, CharSequence rhs, DistanceObject dco) { + this.lhs = lhs; + this.rhs = rhs; + this.dco = dco; + } + public LevenshteinDistance(CharSequence lhs, CharSequence rhs) { + this.lhs = lhs; + this.rhs = rhs; + } + + public int computeLevenshteinDistance() { + int[][] distance = new int[lhs.length() + 1][rhs.length() + 1]; for (int i = 0; i <= lhs.length(); i++) { distance[i][0] = i; } @@ -34,4 +50,32 @@ public class LevenshteinDistance { } return distance[lhs.length()][rhs.length()]; } + + @Override + public DistanceObject call() { + try { + int[][] distance = new int[lhs.length() + 1][rhs.length() + 1]; + + for (int i = 0; i <= lhs.length(); i++) { + distance[i][0] = i; + } + for (int j = 1; j <= rhs.length(); j++) { + distance[0][j] = j; + } + for (int i = 1; i <= lhs.length(); i++) { + for (int j = 1; j <= rhs.length(); j++) { + distance[i][j] = minimum( + distance[i - 1][j] + 1, + distance[i][j - 1] + 1, + distance[i - 1][j - 1] + ((lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1)); + } + } + dco.setDistance(distance[lhs.length()][rhs.length()]); + } catch (Exception ex) { + System.out.println("ex msg: " + ex.getMessage() + "\n"); + dco.setDistance(100); + return dco; + } + return dco; + } } diff --git a/ArtificialAutism/src/main/java/FunctionLayer/MYSQLDatahandler.java b/ArtificialAutism/src/main/java/FunctionLayer/MYSQLDatahandler.java index 8d7fe52f..c8bbc2b5 100644 --- a/ArtificialAutism/src/main/java/FunctionLayer/MYSQLDatahandler.java +++ b/ArtificialAutism/src/main/java/FunctionLayer/MYSQLDatahandler.java @@ -2,25 +2,25 @@ * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. -//https://stackoverflow.com/questions/43935229/hashmap-with-8-million-entries-becomes-slow -//http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/6364/pdf/imm6364.pdf */ package FunctionLayer; import DataLayer.DataMapper; import FunctionLayer.StanfordParser.SentimentAnalyzerTest; import com.google.common.base.Stopwatch; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.MapMaker; -import com.google.common.collect.Multimap; +import edu.stanford.nlp.ie.AbstractSequenceClassifier; +import edu.stanford.nlp.ie.crf.CRFClassifier; +import edu.stanford.nlp.ling.CoreLabel; import edu.stanford.nlp.ling.HasWord; -import edu.stanford.nlp.ling.Label; import edu.stanford.nlp.ling.TaggedWord; import edu.stanford.nlp.ling.Word; import edu.stanford.nlp.parser.lexparser.LexicalizedParser; import edu.stanford.nlp.parser.shiftreduce.ShiftReduceParser; +import edu.stanford.nlp.pipeline.StanfordCoreNLP; import edu.stanford.nlp.process.DocumentPreprocessor; import edu.stanford.nlp.tagger.maxent.MaxentTagger; +import edu.stanford.nlp.trees.GrammaticalStructureFactory; import edu.stanford.nlp.trees.Tree; import edu.stanford.nlp.trees.TreebankLanguagePack; import java.io.IOException; @@ -28,14 +28,23 @@ import java.io.StringReader; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; import java.util.Random; +import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,19 +57,89 @@ public class MYSQLDatahandler { public static final long EXPIRE_TIME_IN_SECONDS = TimeUnit.SECONDS.convert(10, TimeUnit.MINUTES); public static final long EXPIRE_TIME_IN_SECONDS1 = TimeUnit.SECONDS.convert(10, TimeUnit.HOURS); public static MYSQLDatahandler instance = new MYSQLDatahandler(); - public static int SemeticsUpdateCount; + public static int semeticsUpdateCount; public static int threadCounter = 0; - private volatile boolean RefreshMatrixFromDB; - private final ConcurrentMap StringCache; - private List SimilaritySMXList = new ArrayList(); + private volatile boolean refreshMatrixFromDB; + private final ConcurrentMap stringCache; + private LinkedHashMap> lHMSMX = new LinkedHashMap(); private List multiprocessCalculations = new ArrayList(); + private List updatedRows = new ArrayList(); private final Stopwatch stopwatch; private final Stopwatch stopwatch1; + private static String modelPath = "edu/stanford/nlp/models/srparser/englishSR.ser.gz"; + private static String sentimentModel = "edu/stanford/nlp/models/sentiment/sentiment.ser.gz"; + private static String lexParserEnglishRNN = "edu/stanford/nlp/models/lexparser/englishRNN.ser.gz"; + private static String taggerPath = "edu/stanford/nlp/models/pos-tagger/english-left3words/english-left3words-distsim.tagger"; + private static String NERModel = "edu/stanford/nlp/models/ner/english.all.3class.distsim.crf.ser.gz"; + private static MaxentTagger tagger; + private static ShiftReduceParser model; + private static String[] options = {"-maxLength", "100"}; + private static Properties props = new Properties(); + private static Properties propsSentiment = new Properties(); + private static GrammaticalStructureFactory gsf; + private static LexicalizedParser lp; + private static TreebankLanguagePack tlp; + private static AbstractSequenceClassifier classifier; + private static StanfordCoreNLP pipeline; + private static StanfordCoreNLP pipelineSentiment; + + public static AbstractSequenceClassifier getClassifier() { + return classifier; + } + + public static void setClassifier(AbstractSequenceClassifier classifier) { + MYSQLDatahandler.classifier = classifier; + } public MYSQLDatahandler() { this.stopwatch = Stopwatch.createUnstarted(); this.stopwatch1 = Stopwatch.createStarted(); - this.StringCache = new MapMaker().concurrencyLevel(2).makeMap(); + this.stringCache = new MapMaker().concurrencyLevel(2).makeMap(); + } + + public static void shiftReduceParserInitiate() { + try { + classifier = CRFClassifier.getClassifierNoExceptions(NERModel); + } catch (ClassCastException ex) { + Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); + } + model = ShiftReduceParser.loadModel(modelPath, options); + tagger = new MaxentTagger(taggerPath); + lp = LexicalizedParser.loadModel(lexParserEnglishRNN, options); + tlp = lp.getOp().langpack(); + gsf = tlp.grammaticalStructureFactory(); + // set up pipeline properties + props.setProperty("annotators", "tokenize,ssplit,pos,lemma,parse"); + props.setProperty("parse.model", modelPath); + props.setProperty("parse.maxlen", "100"); + props.setProperty("parse.binaryTrees", "true"); + propsSentiment.setProperty("annotators", "tokenize, ssplit, parse, sentiment"); + propsSentiment.setProperty("parse.model", lexParserEnglishRNN); + propsSentiment.setProperty("sentiment.model", sentimentModel); + propsSentiment.setProperty("parse.maxlen", "100"); + // set up pipeline + pipeline = new StanfordCoreNLP(props); + pipelineSentiment = new StanfordCoreNLP(propsSentiment); + } + + public static GrammaticalStructureFactory getGsf() { + return gsf; + } + + public static StanfordCoreNLP getPipeline() { + return pipeline; + } + + public static StanfordCoreNLP getPipelineSentiment() { + return pipelineSentiment; + } + + public static MaxentTagger getTagger() { + return tagger; + } + + public static ShiftReduceParser getModel() { + return model; } private Map getCache() throws SQLException, IOException, CustomError { @@ -78,8 +157,8 @@ public class MYSQLDatahandler { public void initiateMYSQL() throws SQLException, IOException { try { DataMapper.createTables(); - StringCache.putAll(getCache()); - SimilaritySMXList = DataMapper.getAllSementicMatrixes(); + stringCache.putAll(getCache()); + lHMSMX = DataMapper.getAllRelationScores(); } catch (CustomError ex) { Logger.getLogger(MYSQLDatahandler.class .getName()).log(Level.SEVERE, null, ex); @@ -87,34 +166,50 @@ public class MYSQLDatahandler { } public synchronized void checkIfUpdateMatrixes() { - RefreshMatrixFromDB = false; + refreshMatrixFromDB = false; int calculationBoundaries = 10; int updateBadgesInteger = 500; if (stopwatch1.elapsed(TimeUnit.SECONDS) >= EXPIRE_TIME_IN_SECONDS1) { - RefreshMatrixFromDB = true; + refreshMatrixFromDB = true; if (threadCounter == 0) { - try { - SimilaritySMXList = DataMapper.getAllSementicMatrixes(); - stopwatch1.reset(); - } catch (CustomError ex) { - Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); - } + lHMSMX = DataMapper.getAllRelationScores(); + stopwatch1.reset(); } } - if (StringCache.values().size() > 10) { - if (!RefreshMatrixFromDB && multiprocessCalculations.size() <= (calculationBoundaries * calculationBoundaries)) { + if (stringCache.values().size() > 10 && !refreshMatrixFromDB) { + if (multiprocessCalculations.size() <= (calculationBoundaries * calculationBoundaries)) { threadCounter++; - List strList = new ArrayList(StringCache.values()); - SemeticsUpdateCount = new Random().nextInt(strList.size() - 6); - int beginindex = SemeticsUpdateCount; - SemeticsUpdateCount += calculationBoundaries / 2; - int temp = SemeticsUpdateCount; + List strList = new ArrayList(stringCache.values()); + List updateLocal = updatedRows; + int random = -1; + if (!updateLocal.contains(random)) { + updatedRows.add(random); + } + Collections.sort(updateLocal); + while (updateLocal.contains(random)) { + random = new Random().nextInt(strList.size() - 6); + int indexPrev = Collections.binarySearch(updateLocal, random); + int indexNext = Collections.binarySearch(updateLocal, random + 6); + //-1 will always be index 0 + if (indexPrev > 0 && indexNext > 0) { + indexPrev = updateLocal.get(indexPrev); + indexNext = updateLocal.get(indexNext); + } + random = indexPrev < random - 5 && indexNext < random ? random : -1; + } + updatedRows.add(random); + semeticsUpdateCount = random; + int beginindex = semeticsUpdateCount; + semeticsUpdateCount += calculationBoundaries / 2; + int temp = semeticsUpdateCount; + System.out.println("beginindex: " + beginindex + "\ntemp: " + temp + "\n"); List strIndexNavigator = new ArrayList(); strList.subList(beginindex, temp).forEach((str) -> { strIndexNavigator.add(str); multiprocessCalculations.add(str); }); new Thread(() -> { + LinkedHashMap> LHMSMXLocal = lHMSMX; List strIndexNavigatorL = new ArrayList(strIndexNavigator); List strIndexAll = new ArrayList(strList); List randomIndexesToUpdate = new ArrayList(); @@ -127,32 +222,49 @@ public class MYSQLDatahandler { randomIndexesToUpdate.add(str); }); List matrixUpdateList = new ArrayList(); + List> futures = new ArrayList(); + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); strIndexNavigatorL.forEach((str) -> { randomIndexesToUpdate.stream().filter((str1) -> (!str.equals(str1))).forEachOrdered((str1) -> { boolean present = false; if (multiprocessCalculations.contains(str1)) { present = true; - } else { - for (SimilarityMatrix SMX : SimilaritySMXList) { - if (SMX.getPrimaryString().equals(str) && SMX.getSecondaryString().equals(str1)) { - present = true; - break; - } - if (SMX.getPrimaryString().equals(str1) && SMX.getSecondaryString().equals(str)) { - present = true; - break; - } + } else if (LHMSMXLocal.containsKey(str)) { + LinkedHashMap orDefault = LHMSMXLocal.get(str); + if (orDefault.containsKey(str1)) { + present = true; + } + } else if (LHMSMXLocal.containsKey(str1)) { + LinkedHashMap orDefault = LHMSMXLocal.get(str1); + if (orDefault.containsKey(str)) { + present = true; } } if (!present) { SimilarityMatrix SMX = new SimilarityMatrix(str, str1); - double score = SentimentAnalyzerTest.sentimentanalyzing(str, str1); - SMX.setDistance(score); - matrixUpdateList.add(SMX); - SimilaritySMXList.add(SMX); + Callable worker = new SentimentAnalyzerTest(str, str1, SMX); + futures.add(executor.submit(worker)); } }); }); + executor.shutdown(); + try { + System.out.println("finished worker assignment, futures size: " + futures.size() + "\n"); + for (Future future : futures) { + SimilarityMatrix SMX = future.get(); + System.out.println("SMX primary: " + SMX.getPrimaryString() + "\nSMX Secondary: " + SMX.getSecondaryString() + + "\nScore: " + SMX.getDistance() + "\n"); + LinkedHashMap get = lHMSMX.getOrDefault(SMX.getPrimaryString(), null); + if (get == null) { + get = new LinkedHashMap(); + } + get.put(SMX.getSecondaryString(), SMX.getDistance()); + lHMSMX.put(SMX.getPrimaryString(), get); + matrixUpdateList.add(SMX); + } + } catch (InterruptedException | ExecutionException ex) { + Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); + } new Thread(() -> { try { if (!matrixUpdateList.isEmpty()) { @@ -160,6 +272,7 @@ public class MYSQLDatahandler { System.out.println("finished datamapper semetic insert"); } threadCounter--; + System.out.println("\nthreadCounter: " + threadCounter + "\n"); } catch (CustomError ex) { Logger.getLogger(MYSQLDatahandler.class .getName()).log(Level.SEVERE, null, ex); @@ -167,56 +280,73 @@ public class MYSQLDatahandler { }).start(); }). start(); - try { - wait(800); - } catch (InterruptedException ex) { - Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); - } } else { if (threadCounter == 0) { - List strList = new ArrayList(StringCache.values()); - List matrixUpdateList = new ArrayList(); - List randomStrList = new ArrayList(); - int indexes = updateBadgesInteger; - if (indexes >= strList.size()) { - indexes = strList.size() - 1; - } - int beginindexes = new Random().nextInt((strList.size()) - indexes); - strList.subList(beginindexes, beginindexes + indexes).forEach((str) -> { - randomStrList.add(str); - }); - multiprocessCalculations.forEach((str) -> { - randomStrList.forEach((str1) -> { - boolean present = false; - for (SimilarityMatrix SMX : SimilaritySMXList) { - if (SMX.getPrimaryString().equals(str) && SMX.getSecondaryString().equals(str1)) { - present = true; - break; - } - if (SMX.getPrimaryString().equals(str1) && SMX.getSecondaryString().equals(str)) { - present = true; - break; - } - } - if (!present) { - SimilarityMatrix SMX = new SimilarityMatrix(str, str1); - double score = SentimentAnalyzerTest.sentimentanalyzing(str, str1); - SMX.setDistance(score); - matrixUpdateList.add(SMX); - SimilaritySMXList.add(SMX); - } - }); - }); - try { - if (!matrixUpdateList.isEmpty()) { - DataMapper.insertSementicMatrixes(matrixUpdateList); - System.out.println("finished datamapper semetic insert"); + threadCounter++; + new Thread(() -> { + LinkedHashMap> LHMSMXLocal = lHMSMX; + List strList = new ArrayList(stringCache.values()); + List matrixUpdateList = new ArrayList(); + List randomStrList = new ArrayList(); + int indexes = updateBadgesInteger; + if (indexes >= strList.size()) { + indexes = strList.size() - 1; } - } catch (CustomError ex) { - Logger.getLogger(MYSQLDatahandler.class - .getName()).log(Level.SEVERE, null, ex); - } - multiprocessCalculations = new ArrayList(); + int beginindexes = new Random().nextInt((strList.size()) - indexes); + strList.subList(beginindexes, beginindexes + indexes).forEach((str) -> { + randomStrList.add(str); + }); + List> futures = new ArrayList(); + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + multiprocessCalculations.forEach((str) -> { + randomStrList.forEach((str1) -> { + boolean present = false; + if (LHMSMXLocal.containsKey(str)) { + LinkedHashMap orDefault = LHMSMXLocal.get(str); + if (orDefault.containsKey(str1)) { + present = true; + } + } else if (LHMSMXLocal.containsKey(str1)) { + LinkedHashMap orDefault = LHMSMXLocal.get(str1); + if (orDefault.containsKey(str)) { + present = true; + } + } + if (!present) { + SimilarityMatrix SMX = new SimilarityMatrix(str, str1); + Callable worker = new SentimentAnalyzerTest(str, str1, SMX); + futures.add(executor.submit(worker)); + } + }); + }); + executor.shutdown(); + try { + for (Future future : futures) { + SimilarityMatrix SMX = future.get(); + LinkedHashMap get = lHMSMX.getOrDefault(SMX.getPrimaryString(), null); + if (get == null) { + get = new LinkedHashMap(); + } + get.put(SMX.getSecondaryString(), SMX.getDistance()); + lHMSMX.put(SMX.getPrimaryString(), get); + matrixUpdateList.add(SMX); + } + } catch (InterruptedException | ExecutionException ex) { + Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); + } + try { + if (!matrixUpdateList.isEmpty()) { + DataMapper.insertSementicMatrixes(matrixUpdateList); + System.out.println("finished datamapper semetic insert"); + } + } catch (CustomError ex) { + Logger.getLogger(MYSQLDatahandler.class + .getName()).log(Level.SEVERE, null, ex); + } + multiprocessCalculations = new ArrayList(); + updatedRows = new ArrayList(); + threadCounter--; + }).start(); } } } @@ -233,14 +363,15 @@ public class MYSQLDatahandler { strUpdate.addAll(str); try { DataMapper.InsertMYSQLStrings(strUpdate); + } catch (CustomError ex) { Logger.getLogger(MYSQLDatahandler.class .getName()).log(Level.SEVERE, null, ex); } MessageResponseHandler.setStr(new ArrayList()); - int j = StringCache.size() + 1; + int j = stringCache.size() + 1; for (String str1 : strUpdate) { - StringCache.put(j, str1); + stringCache.put(j, str1); j++; } }).start(); @@ -252,85 +383,106 @@ public class MYSQLDatahandler { } } - public String getResponseMsg(String str) throws CustomError { + public synchronized String getResponseMsg(String str) throws CustomError { + str = str.trim(); + if (str.startsWith("<@")) { + str = str.substring(str.indexOf("> ") + 2); + } + final LinkedHashMap> LHMSMXLocal = lHMSMX; + ConcurrentMap strArrs = stringCache; double Score = -10000; - SimilarityMatrix SMXreturn = null; - List strLocal = new ArrayList(StringCache.values()); - for (String str1 : strLocal) { - if (str.equals(str1)) { - Iterator SMXITR = SimilaritySMXList.iterator(); - while (SMXITR.hasNext()) { - SimilarityMatrix SMX = SMXITR.next(); - if (SMX.getPrimaryString().equals(str) || SMX.getSecondaryString().equals(str)) { - double smxDistance = SMX.getDistance(); + SimilarityMatrix SMXreturn = new SimilarityMatrix("", ""); + System.out.println("pre mostSimilarSTR \n"); + String mostSimilarSTR = mostSimilar(str, strArrs); + if (!mostSimilarSTR.isEmpty()) { + System.out.println("mostSimilarSTR; " + mostSimilarSTR + "\n"); + LinkedHashMap orDefault = LHMSMXLocal.getOrDefault(mostSimilarSTR, null); + if (orDefault != null) { + for (Entry entrySet : orDefault.entrySet()) { + double smxDistance = entrySet.getValue(); + if (smxDistance > Score) { + Score = smxDistance; + SMXreturn = new SimilarityMatrix(mostSimilarSTR, entrySet.getKey(), smxDistance); + } + } + } + for (Entry> values1 : LHMSMXLocal.entrySet()) { + LinkedHashMap value = values1.getValue(); + for (Entry keystr : value.entrySet()) { + if (keystr.getKey().equals(mostSimilarSTR)) { + double smxDistance = keystr.getValue(); if (smxDistance > Score) { Score = smxDistance; - SMXreturn = SMX; + SMXreturn = new SimilarityMatrix(values1.getKey(), keystr.getKey(), smxDistance); } } } - break; } - } - if (SMXreturn != null) { - if (SMXreturn.getPrimaryString().equals(str)) { - return SMXreturn.getSecondaryString(); - } else { - return SMXreturn.getPrimaryString(); - } - } - String[] toArray = strLocal.toArray(new String[strLocal.size()]); - String mostSimilarSTR = mostSimilar(str, toArray); - Iterator SMXITR = SimilaritySMXList.iterator(); - while (SMXITR.hasNext()) { - System.out.println("mostSimilarSTR; " + mostSimilarSTR + "\n"); - mostSimilarSTR = mostSimilarSTR.trim(); - SimilarityMatrix SMX = SMXITR.next(); - if (SMX.getPrimaryString().trim().equals(mostSimilarSTR) || SMX.getSecondaryString().trim().equals(mostSimilarSTR)) { - double smxDistance = SMX.getDistance(); - if (smxDistance > Score) { - Score = smxDistance; - SMXreturn = SMX; + if (!SMXreturn.getPrimaryString().isEmpty()) { + if (SMXreturn.getPrimaryString().equals(mostSimilarSTR)) { + return SMXreturn.getSecondaryString(); + } else { + return SMXreturn.getPrimaryString(); } } } - if (SMXreturn != null) { - if (SMXreturn.getPrimaryString().equals(str)) { - return SMXreturn.getSecondaryString(); - } else { - return SMXreturn.getPrimaryString(); + System.out.println("none within 8 range"); + ConcurrentMap strCache = stringCache; + ConcurrentMap> futureslocal = new MapMaker().concurrencyLevel(2).makeMap(); + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + for (String str1 : strCache.values()) { + if (!str.equals(str1)) { + Callable worker = new SentimentAnalyzerTest(str, str1, new SimilarityMatrix(str, str1)); + futureslocal.put(futureslocal.size() + 1, executor.submit(worker)); } } - SMXITR = SimilaritySMXList.iterator(); - while (SMXITR.hasNext()) { - SimilarityMatrix SMX = SMXITR.next(); - if (SMX.getPrimaryString().contains(mostSimilarSTR) || SMX.getSecondaryString().contains(mostSimilarSTR)) { - double smxDistance = SMX.getDistance(); - if (smxDistance > Score) { - Score = smxDistance; + executor.shutdown(); + int index = 0; + for (Future future : futureslocal.values()) { + try { + SimilarityMatrix SMX = future.get(); + double distance = SMX.getDistance(); + System.out.println("index: " + index + "\nfutures size: " + futureslocal.values().size() + "\nScore: " + SMX.getDistance() + "\nSecondary: " + + SMX.getSecondaryString() + "\nPrimary: " + SMX.getPrimaryString() + "\n"); + if (distance > Score) { + Score = distance; SMXreturn = SMX; } + } catch (InterruptedException | ExecutionException ex) { + System.out.println("ex: " + ex.getMessage() + "\n"); } + index++; } - if (SMXreturn != null) { - if (SMXreturn.getPrimaryString().equals(str)) { - return SMXreturn.getSecondaryString(); - } else { - return SMXreturn.getPrimaryString(); - } - } - return "how did you manage to reach this, AAAAAAAAAAAA end my suffering"; + System.out.println("Reached end: secondary: " + SMXreturn.getSecondaryString() + "\nPrimarY: " + SMXreturn.getPrimaryString() + + "\nScore: " + SMXreturn.getDistance()); + return SMXreturn.getSecondaryString(); } - public String mostSimilar(String toBeCompared, String[] strings) { - int minDistance = Integer.MAX_VALUE; + public String mostSimilar(String toBeCompared, ConcurrentMap concurrentStrings) { + int minDistance = 8; String similar = ""; - for (String str : strings) { - int d = LevenshteinDistance.computeLevenshteinDistance(str, toBeCompared); - if (d < minDistance) { - minDistance = d; - similar = str; + List> futures = new ArrayList(); + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + concurrentStrings.values().stream().map((str) -> new LevenshteinDistance(str, toBeCompared, new DistanceObject())).forEachOrdered((worker) -> { + futures.add(executor.submit(worker)); + }); + executor.shutdown(); + try { + for (Future future : futures) { + DistanceObject d = future.get(); + try { + int distance = d.getDistance(); + System.out.println("distance: " + distance + "\n"); + if (distance < minDistance) { + minDistance = distance; + similar = d.getSentence(); + } + } catch (NullPointerException ex) { + System.out.println("failed future\n"); + } } + } catch (InterruptedException | ExecutionException ex) { + Logger.getLogger(MYSQLDatahandler.class.getName()).log(Level.SEVERE, null, ex); } return similar; } @@ -402,6 +554,30 @@ public class MYSQLDatahandler { if (str1.contains("{white}")) { str1 = str1.replace("{white}", " "); } + if (str1.contains("{fullblue}")) { + str1 = str1.replace("{fullblue}", " "); + } + if (str1.contains("{cyan}")) { + str1 = str1.replace("{cyan}", " "); + } + if (str1.contains("{lime}")) { + str1 = str1.replace("{lime}", " "); + } + if (str1.contains("{deeppink}")) { + str1 = str1.replace("{deeppink}", " "); + } + if (str1.contains("{slategray}")) { + str1 = str1.replace("{slategray}", " "); + } + if (str1.contains("{dodgerblue}")) { + str1 = str1.replace("{dodgerblue}", " "); + } + if (str1.contains("{black}")) { + str1 = str1.replace("{black}", " "); + } + if (str1.contains("{orangered}")) { + str1 = str1.replace("{orangered}", " "); + } str1 = str1.trim(); if (str1.length() > 2 && (!str1.startsWith("!"))) { strlistreturn.add(str1); @@ -410,38 +586,9 @@ public class MYSQLDatahandler { return strlistreturn; } - /* - public static List cutLongsFromEmotes(List str) { - List strreturn = new ArrayList(); - int emotesTraceLong = 17; - for (String str1 : str) { - StringBuilder SB = new StringBuilder(); - int counter = 0; - int i = 0; - for (Character c : str1.toCharArray()) { - i++; - if (Character.isDigit(c)) { - counter++; - if (counter > emotesTraceLong && str1.length() > i + 2) { - SB.append(str1.substring(0, i - emotesTraceLong)); - SB.append(str1.substring(i + 1, str1.length())); - } - } else { - counter = 0; - } - } - if (SB.toString().isEmpty()) { - strreturn.add(str1); - } else { - strreturn.add(SB.toString()); - } - } - return strreturn; - } - */ private List removeSlacks(List str) { - ShiftReduceParser model = SentimentAnalyzerTest.getModel(); - MaxentTagger tagger = SentimentAnalyzerTest.getTagger(); + ShiftReduceParser model = getModel(); + MaxentTagger tagger = getTagger(); List taggedWords; List strreturn = new ArrayList(); for (String str1 : str) { @@ -481,9 +628,10 @@ public class MYSQLDatahandler { } if (addCounter > 3) { boolean tooclosematch = false; - for (String strVals : StringCache.values()) { - double Distance = LevenshteinDistance.computeLevenshteinDistance(strVals, str1); - int maxpermittedDistance = 5; + for (String strVals : stringCache.values()) { + LevenshteinDistance leven = new LevenshteinDistance(strVals, str1); + double Distance = leven.computeLevenshteinDistance(); + int maxpermittedDistance = 2; if (Distance < maxpermittedDistance) { tooclosematch = true; break; @@ -504,153 +652,4 @@ public class MYSQLDatahandler { } return strreturn; } - - /** - * - * @throws CustomError - * @deprecated - */ - public synchronized void calculateStrings() throws CustomError { - //linkedhashmap? - int initiallimit = 5; - int listindex = 0; - List WS4JList = DataMapper.getAllSementicMatrixes(); - List WS4JListUpdate = new ArrayList(); - List sentencesList = DataMapper.getAllStrings(); - for (int i = 1; i < initiallimit; i++) { - if (!sentencesList.get(i).isEmpty()) { - //System.out.print("i: " + i + "\n sentencesList i: " + sentencesList.get(i) + "\n"); - String[] words1 = sentencesList.get(i).split(" "); - for (String words11 : words1) { - if (!words11.isEmpty() && words11.length() > 3) { - String str = words11; - if (!str.isEmpty() && str.length() > 3) { - //SecondaryPredicate, no secondary key present with word - Predicate SecondaryPredicate = e -> str.equals(e.getSecondaryString()); - //no primary key present with the word - if (!WS4JList.stream().filter(e -> str.equals(e.getPrimaryString())).findAny().isPresent()) { - WS4JListUpdate = createWS4JWordMatrix(str, sentencesList, WS4JListUpdate, WS4JList, SecondaryPredicate); - for (; listindex < WS4JListUpdate.size(); listindex++) { - WS4JList.add(WS4JListUpdate.get(listindex)); - } - } - } - } - } - } - } - //System.out.println("\nWS4JListUpdate size: " + WS4JListUpdate.size()); - DataMapper.insertSementicMatrixes(WS4JListUpdate); - } - - /** - * - * @param str - * @param strlist - * @param ws4jlist - * @param oldlist - * @param SecondaryPredicate - * @return - * @deprecated - */ - public List createWS4JWordMatrix(String str, List strlist, List ws4jlist, - List oldlist, Predicate SecondaryPredicate) { - for (String str1 : strlist) { - if (!str1.isEmpty()) { - String[] words1 = str1.split(" "); - for (int j = 0; j < words1.length; j++) { - if (!words1[j].isEmpty() && words1[j].length() > 3) { - String strword = words1[j]; - if (!strword.isEmpty() && strword.length() > 3 && !strword.equals(str)) { - Predicate PrimaryPredicate = e -> strword.equals(e.getPrimaryString()); - if (!oldlist.stream().filter(PrimaryPredicate.and(SecondaryPredicate)).findAny().isPresent()) { - //System.out.println("creating SimilarityMatrix with STR: " + str + "\n strword: " + strword + "\n"); - SimilarityMatrix ws4j = new SimilarityMatrix(str, strword); - /* - double addingDistance = ws4j.getDistanceCalculations(); - if (addingDistance > 0.00) { - //System.out.println("added! \n"); - ws4j.setDistance(addingDistance); - ws4jlist.add(ws4j); - } - */ - } - } - } - } - } - } - return ws4jlist; - } - - /** - * Stanford Parser method to update calculations to the DB - * - * @deprecated - * @throws FunctionLayer.CustomError - */ - public void sentimentAnalyzingStringsToDB() throws CustomError { - - List sentencesList = DataMapper.getAllStrings(); - List WS4JList = DataMapper.getAllSementicMatrixes(); - List WS4JListUpdate = new ArrayList(); - int listindex = 0; - for (int i = 0; i < sentencesList.size() - 3000; i++) { - String str = sentencesList.get(i); - if (!str.isEmpty() && str.length() > 3) { - //System.out.println("i: " + i + "\n"); - Predicate SecondaryPredicate = e -> str.equals(e.getSecondaryString()); - if (!WS4JList.stream().filter(e -> str.equals(e.getPrimaryString())).findAny().isPresent()) { - //WS4JListUpdate = addStringMatrixes(str, sentencesList, SecondaryPredicate, WS4JListUpdate, WS4JList); - for (; listindex < WS4JListUpdate.size(); listindex++) { - WS4JList.add(WS4JListUpdate.get(listindex)); - } - } - } - } - // System.out.println("\n WS4JListUpdate size: " + WS4JListUpdate.size()); - DataMapper.insertSementicMatrixes(WS4JListUpdate); - } - - /** - * @deprecated @param str Primary string which is checked, the filter - * ensures primary string has not been calculated yet - * @param sentencesList the full string list where each unique primary has - * to calculate its value to the rest of the DB - * @param SecondaryPredicate ensures primary string is not already - * calculated somewhere with another string - * @param WS4JListUpdate Matrix list to update in DB with new Sentences - * @param OldWS4JList Check if str1 already has primary entry with - * co-responding SecondaryPredicate - * @return Updated List which has to be inserted to the DB - */ - private List addStringMatrixes(String str, List sentencesList, - Predicate SecondaryPredicate, List WS4JListUpdate, - List OldWS4JList, LexicalizedParser lp, TreebankLanguagePack tlp) { - double valuerange = -100.0; - for (int i = 0; i < sentencesList.size(); i++) { - String str1 = sentencesList.get(i); - if (!str1.isEmpty() && str1.length() > 3) { - Predicate PrimaryPredicate = e -> str1.equals(e.getPrimaryString()); - if (!OldWS4JList.stream().filter(PrimaryPredicate.and(SecondaryPredicate)).findAny().isPresent()) { - double s = -100.0; - if (s > valuerange) { - SimilarityMatrix SMX = new SimilarityMatrix(str, str1); - SMX.setDistance(s); - /* - System.out.println("SMX added: \n Primary: " + SMX.getPrimaryString() + "\n Secondary: " + SMX.getSecondaryString() - + "\n Score: " + SMX.getDistance() + "\n"); - */ - WS4JListUpdate.add(SMX); - } - } - } - } - /* - str parameter is primary and not used as primary if reaching here - secondary predicate ensures primary does not already exist as secondary with co-responding strlist primary - */ - return WS4JListUpdate; - } - } diff --git a/ArtificialAutism/src/main/java/FunctionLayer/MessageResponseHandler.java b/ArtificialAutism/src/main/java/FunctionLayer/MessageResponseHandler.java index 29dfcdf9..d8c2aa1f 100644 --- a/ArtificialAutism/src/main/java/FunctionLayer/MessageResponseHandler.java +++ b/ArtificialAutism/src/main/java/FunctionLayer/MessageResponseHandler.java @@ -7,8 +7,6 @@ package FunctionLayer; import java.util.ArrayList; import java.util.List; -//https://www.programcreek.com/java-api-examples/index.php?source_dir=simmetrics-master/simmetrics-core/src/main/java/org/simmetrics/metrics/JaroWinkler.java# -//https://stackoverflow.com/questions/36032958/semantic-matching-in-ws4j-at-sentence-level /** * @@ -29,6 +27,9 @@ public class MessageResponseHandler { public static void getMessage(String message) { if (message != null && !message.isEmpty()) { message = message.replace("@", ""); + if (message.startsWith("<>")) { + message = message.substring(message.indexOf(">")); + } if (message.startsWith("[ *")) { message = message.substring(message.indexOf("]")); } diff --git a/ArtificialAutism/src/main/java/FunctionLayer/StanfordParser/SentimentAnalyzerTest.java b/ArtificialAutism/src/main/java/FunctionLayer/StanfordParser/SentimentAnalyzerTest.java index 20c7b944..8e369c35 100644 --- a/ArtificialAutism/src/main/java/FunctionLayer/StanfordParser/SentimentAnalyzerTest.java +++ b/ArtificialAutism/src/main/java/FunctionLayer/StanfordParser/SentimentAnalyzerTest.java @@ -1,20 +1,21 @@ package FunctionLayer.StanfordParser; import FunctionLayer.LevenshteinDistance; +import FunctionLayer.MYSQLDatahandler; +import FunctionLayer.SimilarityMatrix; +import edu.stanford.nlp.ie.AbstractSequenceClassifier; import edu.stanford.nlp.ling.CoreAnnotations; import edu.stanford.nlp.ling.CoreLabel; import edu.stanford.nlp.ling.HasWord; import edu.stanford.nlp.ling.IndexedWord; -import edu.stanford.nlp.ling.Label; import edu.stanford.nlp.ling.TaggedWord; import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations; -import edu.stanford.nlp.parser.lexparser.LexicalizedParser; import edu.stanford.nlp.parser.shiftreduce.ShiftReduceParser; import edu.stanford.nlp.pipeline.Annotation; import edu.stanford.nlp.pipeline.StanfordCoreNLP; import edu.stanford.nlp.process.DocumentPreprocessor; -import edu.stanford.nlp.process.Tokenizer; import edu.stanford.nlp.sentiment.SentimentCoreAnnotations; +import edu.stanford.nlp.sequences.DocumentReaderAndWriter; import edu.stanford.nlp.tagger.maxent.MaxentTagger; import edu.stanford.nlp.trees.Constituent; import edu.stanford.nlp.trees.GrammaticalRelation; @@ -22,7 +23,6 @@ import edu.stanford.nlp.trees.GrammaticalStructure; import edu.stanford.nlp.trees.GrammaticalStructureFactory; import edu.stanford.nlp.trees.Tree; import edu.stanford.nlp.trees.TreeCoreAnnotations; -import edu.stanford.nlp.trees.TreebankLanguagePack; import edu.stanford.nlp.trees.TypedDependency; import edu.stanford.nlp.trees.tregex.gui.Tdiff; import edu.stanford.nlp.util.CoreMap; @@ -30,8 +30,9 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Properties; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; import org.ejml.simple.SimpleMatrix; /* @@ -43,217 +44,227 @@ import org.ejml.simple.SimpleMatrix; * * @author install1 */ -public class SentimentAnalyzerTest { +public class SentimentAnalyzerTest implements Callable { - private static String modelPath = "edu/stanford/nlp/models/srparser/englishSR.ser.gz"; - private static String sentimentModel = "edu/stanford/nlp/models/sentiment/sentiment.ser.gz"; - private static String parserModelPathUD = "edu/stanford/nlp/models/parser/nndep/english_UD.gz"; - private static String lexParserEnglishRNN = "edu/stanford/nlp/models/lexparser/englishRNN.ser.gz"; - private static String taggerPath = "edu/stanford/nlp/models/pos-tagger/english-left3words/english-left3words-distsim.tagger"; - private static MaxentTagger tagger; - private static ShiftReduceParser model; - private static String[] options = {"-maxLength", "100"}; - private static LexicalizedParser lp; - private static TreebankLanguagePack tlp; - private static Properties props = new Properties(); - private static Properties propsSentiment = new Properties(); - private static GrammaticalStructureFactory gsf; - private static StanfordCoreNLP pipeline; - private static StanfordCoreNLP pipelineSentiment; + private String str; + private String str1; + private SimilarityMatrix smxParam; + private ShiftReduceParser model; + private MaxentTagger tagger; + private GrammaticalStructureFactory gsf; + private StanfordCoreNLP pipeline; + private StanfordCoreNLP pipelineSentiment; + private AbstractSequenceClassifier classifier; - public static void shiftReduceParserInitiate() { - model = ShiftReduceParser.loadModel(modelPath, options); - tagger = new MaxentTagger(taggerPath); - lp = LexicalizedParser.loadModel(lexParserEnglishRNN, options); - tlp = lp.getOp().langpack(); - gsf = tlp.grammaticalStructureFactory(); - props.setProperty("annotators", "tokenize,ssplit,pos,lemma,parse"); - // set up pipeline properties - props.setProperty("parse.model", modelPath); - // use faster shift reduce parser - props.setProperty("parse.maxlen", "100"); - props.setProperty("parse.binaryTrees", "true"); - propsSentiment.setProperty("annotators", "tokenize, ssplit, parse, sentiment"); - propsSentiment.setProperty("parse.model", lexParserEnglishRNN); - propsSentiment.setProperty("parse.maxlen", "100"); - pipeline = new StanfordCoreNLP(props); - pipelineSentiment = new StanfordCoreNLP(propsSentiment); + public SentimentAnalyzerTest(String str, String str1, SimilarityMatrix smxParam) { + this.str = str; + this.str1 = str1; + this.smxParam = smxParam; + model = MYSQLDatahandler.getModel(); + tagger = MYSQLDatahandler.getTagger(); + pipeline = MYSQLDatahandler.getPipeline(); + pipelineSentiment = MYSQLDatahandler.getPipelineSentiment(); + gsf = MYSQLDatahandler.getGsf(); + classifier = MYSQLDatahandler.getClassifier(); } - public static ShiftReduceParser getModel() { - return model; - } - - public static MaxentTagger getTagger() { - return tagger; - } - - public static double sentimentanalyzing(String str, String str1) { - double score = -100.0; - List> taggedwordlist1 = new ArrayList(); - List> taggedwordlist2 = new ArrayList(); - DocumentPreprocessor tokenizer = new DocumentPreprocessor(new StringReader(str1)); - for (List sentence : tokenizer) { - List tagged1 = tagger.tagSentence(sentence); - Tree tree = model.apply(tagged1); - ArrayList taggedYield = tree.taggedYield(); - taggedwordlist1.add(taggedYield); - } - tokenizer = new DocumentPreprocessor(new StringReader(str)); - for (List sentence : tokenizer) { - List tagged1 = tagger.tagSentence(sentence); - Tree tree = model.apply(tagged1); - ArrayList taggedYield = tree.taggedYield(); - taggedwordlist2.add(taggedYield); - } - int counter = 0; - int counter1 = 0; - for (List taggedlist2 : taggedwordlist2) { - counter += taggedlist2.size(); - } - for (List taggedlist1 : taggedwordlist1) { - counter1 += taggedlist1.size(); - } - int overValue = counter >= counter1 ? counter - counter1 : counter1 - counter; - overValue *= 16; - while (overValue > 0) { - overValue--; - score--; - } - System.out.println("Score Post overValue: " + score + "\n"); - for (List TGWList : taggedwordlist1) { - for (TaggedWord TGW : TGWList) { - List tgwlist1 = new ArrayList(); - for (List taggedlist2 : taggedwordlist2) { - for (TaggedWord TGW1 : taggedlist2) { - if (TGW.tag().equals(TGW1.tag()) && !TGW.tag().equals(":") && !tgwlist1.contains(TGW1.tag())) { - score += 64; - tgwlist1.add(TGW.tag()); - } - } - } + @Override + public SimilarityMatrix call() { + try { + Double score = -100.0; + List> taggedwordlist1 = new ArrayList(); + List> taggedwordlist2 = new ArrayList(); + DocumentPreprocessor tokenizer = new DocumentPreprocessor(new StringReader(str1)); + for (List sentence : tokenizer) { + taggedwordlist1.add(model.apply(tagger.tagSentence(sentence)).taggedYield()); } - } - // System.out.println("Score: " + score); - Annotation annotation = new Annotation(str1); - pipeline.annotate(annotation); - List sentenceConstituencyParseList = new ArrayList(); - for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) { - Tree sentenceConstituencyParse = sentence.get(TreeCoreAnnotations.TreeAnnotation.class); - sentenceConstituencyParseList.add(sentenceConstituencyParse); - } - Annotation annotation1 = new Annotation(str); - pipeline.annotate(annotation1); - for (CoreMap sentence : annotation1.get(CoreAnnotations.SentencesAnnotation.class)) { - Tree sentenceConstituencyParse = sentence.get(TreeCoreAnnotations.TreeAnnotation.class); - GrammaticalStructure gs = gsf.newGrammaticalStructure(sentenceConstituencyParse); - Collection allTypedDependencies = gs.allTypedDependencies(); - List filerTreeContent = new ArrayList(); - for (Tree sentenceConstituencyParse1 : sentenceConstituencyParseList) { - Set inT1notT2 = Tdiff.markDiff(sentenceConstituencyParse, sentenceConstituencyParse1); - Set inT2notT1 = Tdiff.markDiff(sentenceConstituencyParse1, sentenceConstituencyParse); - List constiLabels = new ArrayList(); - for (Constituent consti : inT1notT2) { - for (Constituent consti1 : inT2notT1) { - if (consti.value().equals(consti1.value()) && !constiLabels.contains(consti.value())) { - //System.out.println("consti value: " + consti.value() + "\n"); - score += 64; //256 - constiLabels.add(consti.value()); + tokenizer = new DocumentPreprocessor(new StringReader(str)); + for (List sentence : tokenizer) { + taggedwordlist2.add(model.apply(tagger.tagSentence(sentence)).taggedYield()); + } + int counter = 0; + int counter1 = 0; + counter = taggedwordlist2.stream().map((taggedlist2) -> taggedlist2.size()).reduce(counter, Integer::sum); + counter1 = taggedwordlist1.stream().map((taggedlist1) -> taggedlist1.size()).reduce(counter1, Integer::sum); + int overValue = counter >= counter1 ? counter - counter1 : counter1 - counter; + overValue *= 16; + score -= overValue; + List tgwlistIndex = new ArrayList(); + taggedwordlist1.forEach((TGWList) -> { + TGWList.forEach((TaggedWord) -> { + if (!tgwlistIndex.contains(TaggedWord.tag()) && !TaggedWord.tag().equals(":")) { + tgwlistIndex.add(TaggedWord.tag()); + } + }); + }); + AtomicInteger runCount = new AtomicInteger(0); + taggedwordlist2.forEach((TGWList) -> { + TGWList.forEach((TaggedWord) -> { + if (tgwlistIndex.contains(TaggedWord.tag())) { + tgwlistIndex.remove(TaggedWord.tag()); + runCount.getAndIncrement(); + } + }); + }); + score += runCount.get() * 64; + Annotation annotation = new Annotation(str1); + pipeline.annotate(annotation); + List sentenceConstituencyParseList = new ArrayList(); + for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree sentenceConstituencyParse = sentence.get(TreeCoreAnnotations.TreeAnnotation.class); + sentenceConstituencyParseList.add(sentenceConstituencyParse); + } + Annotation annotation1 = new Annotation(str); + pipeline.annotate(annotation1); + List nerList = new ArrayList(); + for (CoreMap sentence : annotation1.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree sentenceConstituencyParse = sentence.get(TreeCoreAnnotations.TreeAnnotation.class); + GrammaticalStructure gs = gsf.newGrammaticalStructure(sentenceConstituencyParse); + Collection allTypedDependencies = gs.allTypedDependencies(); + List filerTreeContent = new ArrayList(); + for (Tree sentenceConstituencyParse1 : sentenceConstituencyParseList) { + Set inT1notT2 = Tdiff.markDiff(sentenceConstituencyParse, sentenceConstituencyParse1); + Set inT2notT1 = Tdiff.markDiff(sentenceConstituencyParse1, sentenceConstituencyParse); + List constiLabels = new ArrayList(); + for (Constituent consti : inT1notT2) { + for (Constituent consti1 : inT2notT1) { + if (consti.value().equals(consti1.value()) && !constiLabels.contains(consti.value())) { + score += 64; //256 + constiLabels.add(consti.value()); + } } } - } - GrammaticalStructure gs1 = gsf.newGrammaticalStructure(sentenceConstituencyParse1); - Collection allTypedDependencies1 = gs1.allTypedDependencies(); - for (TypedDependency TDY1 : allTypedDependencies1) { - IndexedWord dep = TDY1.dep(); - IndexedWord gov = TDY1.gov(); - GrammaticalRelation grammaticalRelation = gs.getGrammaticalRelation(gov, dep); - if (grammaticalRelation.isApplicable(sentenceConstituencyParse)) { - score += 900; - //System.out.println("grammaticalRelation applicable: " + score + "\n"); + GrammaticalStructure gs1 = gsf.newGrammaticalStructure(sentenceConstituencyParse1); + Collection allTypedDependencies1 = gs1.allTypedDependencies(); + for (TypedDependency TDY1 : allTypedDependencies1) { + IndexedWord dep = TDY1.dep(); + IndexedWord gov = TDY1.gov(); + GrammaticalRelation grammaticalRelation = gs.getGrammaticalRelation(gov, dep); + if (grammaticalRelation.isApplicable(sentenceConstituencyParse)) { + score += 900; + } + GrammaticalRelation reln = TDY1.reln(); + if (reln.isApplicable(sentenceConstituencyParse)) { + score += 256; + } } - GrammaticalRelation reln = TDY1.reln(); - if (reln.isApplicable(sentenceConstituencyParse)) { - score += 256; + for (TypedDependency TDY : allTypedDependencies) { + IndexedWord dep = TDY.dep(); + IndexedWord gov = TDY.gov(); + GrammaticalRelation grammaticalRelation = gs1.getGrammaticalRelation(gov, dep); + if (grammaticalRelation.isApplicable(sentenceConstituencyParse)) { + score += 900; + } + GrammaticalRelation reln = TDY.reln(); + if (reln.isApplicable(sentenceConstituencyParse1)) { + score += 256; + } } - } - for (TypedDependency TDY : allTypedDependencies) { - IndexedWord dep = TDY.dep(); - IndexedWord gov = TDY.gov(); - GrammaticalRelation grammaticalRelation = gs1.getGrammaticalRelation(gov, dep); - if (grammaticalRelation.isApplicable(sentenceConstituencyParse)) { - score += 900; - //System.out.println("grammaticalRelation applicable: " + score + "\n"); - } - GrammaticalRelation reln = TDY.reln(); - if (reln.isApplicable(sentenceConstituencyParse1)) { - score += 256; - } - } - for (CoreLabel LBW : sentenceConstituencyParse.taggedLabeledYield()) { - for (CoreLabel LBW1 : sentenceConstituencyParse1.taggedLabeledYield()) { - if (LBW.lemma().equals(LBW1.lemma()) && !filerTreeContent.contains(LBW.lemma())) { + AtomicInteger runCount1 = new AtomicInteger(0); + sentenceConstituencyParse.taggedLabeledYield().forEach((LBW) -> { + sentenceConstituencyParse1.taggedLabeledYield().stream().filter((LBW1) -> (LBW.lemma().equals(LBW1.lemma()) + && !filerTreeContent.contains(LBW.lemma()))).map((_item) -> { filerTreeContent.add(LBW.lemma()); - score += 1500; - //System.out.println("lemma: " + LBW.lemma() + "\n"); - } + return _item; + }).forEachOrdered((_item) -> { + runCount1.getAndIncrement(); + }); + }); + score += runCount1.get() * 1500; + } + } + Annotation annotationSentiment1 = pipelineSentiment.process(str); + List simpleSMXlist = new ArrayList(); + List simpleSMXlistVector = new ArrayList(); + List sentiment1 = new ArrayList(); + List sentiment2 = new ArrayList(); + for (CoreMap sentence : annotationSentiment1.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); + sentiment1.add(RNNCoreAnnotations.getPredictedClass(tree)); + SimpleMatrix predictions = RNNCoreAnnotations.getPredictions(tree); + SimpleMatrix nodeVector = RNNCoreAnnotations.getNodeVector(tree); + simpleSMXlist.add(predictions); + simpleSMXlistVector.add(nodeVector); + } + annotationSentiment1 = pipelineSentiment.process(str1); + for (CoreMap sentence : annotationSentiment1.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); + sentiment2.add(RNNCoreAnnotations.getPredictedClass(tree)); + SimpleMatrix predictions = RNNCoreAnnotations.getPredictions(tree); + SimpleMatrix nodeVector = RNNCoreAnnotations.getNodeVector(tree); + score = simpleSMXlist.stream().map((simpleSMX) -> predictions.dot(simpleSMX) * 100).map((dot) -> dot > 50 ? dot - 50 : 50 - dot).map((subtracter) -> { + subtracter *= 25; + return subtracter; + }).map((subtracter) -> subtracter).reduce(score, (accumulator, _item) -> accumulator - _item); + for (SimpleMatrix simpleSMX : simpleSMXlistVector) { + double dot = nodeVector.dot(simpleSMX); + double elementSum = nodeVector.kron(simpleSMX).elementSum(); + elementSum = Math.round(elementSum * 100.0) / 100.0; + if (dot < 0.1) { + score += 256; + } + if (elementSum < 0.1 && elementSum > 0.0) { + score += 1300; + } else if (elementSum > 0.1 && elementSum < 1.0) { + score -= 1100; + } else { + score -= 1424; } } } - } - Annotation annotationSentiment1 = pipelineSentiment.process(str); - List simpleSMXlist = new ArrayList(); - List simpleSMXlistVector = new ArrayList(); - for (CoreMap sentence : annotationSentiment1.get(CoreAnnotations.SentencesAnnotation.class)) { - Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); - SimpleMatrix predictions = RNNCoreAnnotations.getPredictions(tree); - SimpleMatrix nodeVector = RNNCoreAnnotations.getNodeVector(tree); - simpleSMXlist.add(predictions); - simpleSMXlistVector.add(nodeVector); - } - annotationSentiment1 = pipelineSentiment.process(str1); - for (CoreMap sentence : annotationSentiment1.get(CoreAnnotations.SentencesAnnotation.class)) { - Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); - SimpleMatrix predictions = RNNCoreAnnotations.getPredictions(tree); - SimpleMatrix nodeVector = RNNCoreAnnotations.getNodeVector(tree); - for (SimpleMatrix simpleSMX : simpleSMXlist) { - double dot = predictions.dot(simpleSMX) * 100; - //System.out.println("dot value: " + dot + "\n"); - double subtracter = dot > 50 ? dot - 50 : 50 - dot; - System.out.println("score pre dot: " + score + "\nsubtracter: " + subtracter + "\n"); - subtracter *= 25; - while (subtracter > 0) { - subtracter--; - score--; + score -= (sentiment1.size() > sentiment2.size() ? sentiment1.size() - sentiment2.size() : sentiment2.size() - sentiment1.size()) * 500; + DocumentReaderAndWriter readerAndWriter = classifier.makePlainTextReaderAndWriter(); + List classifyRaw1 = classifier.classifyRaw(str, readerAndWriter); + List classifyRaw2 = classifier.classifyRaw(str1, readerAndWriter); + score -= (classifyRaw1.size() > classifyRaw2.size() ? classifyRaw1.size() - classifyRaw2.size() : classifyRaw2.size() - classifyRaw1.size()) * 200; + Annotation annotationSentiment = pipelineSentiment.process(str); + int mainSentiment1 = 0; + int longest1 = 0; + int mainSentiment2 = 0; + int longest2 = 0; + for (CoreMap sentence : annotationSentiment.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); + int sentiment = RNNCoreAnnotations.getPredictedClass(tree); + String partText = sentence.toString(); + if (partText.length() > longest1) { + mainSentiment1 = sentiment; + longest1 = partText.length(); } - System.out.println("score post dot: " + score + "\n"); } - for (SimpleMatrix simpleSMX : simpleSMXlistVector) { - double dot = nodeVector.dot(simpleSMX); - double elementSum = nodeVector.kron(simpleSMX).elementSum(); - elementSum = Math.round(elementSum * 100.0) / 100.0; - System.out.println("kron SMX elementSum: " + elementSum + "\n"); - if (dot < 0.1) { - // System.out.println("\ndot VECTOR: " + dot + "\n"); - score += 256; + annotationSentiment = pipelineSentiment.process(str1); + for (CoreMap sentence : annotationSentiment.get(CoreAnnotations.SentencesAnnotation.class)) { + Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class); + int sentiment = RNNCoreAnnotations.getPredictedClass(tree); + SimpleMatrix predictions = RNNCoreAnnotations.getPredictions(tree); + String partText = sentence.toString(); + if (partText.length() > longest2) { + mainSentiment2 = sentiment; + longest2 = partText.length(); } - if (elementSum < 0.1 && elementSum > 0.0) { - score += 1300; - } else if (elementSum > 0.1 && elementSum < 1.0) { - score -= 1100; + } + if (longest1 != longest2) { + long deffLongest = longest1 > longest2 ? longest1 : longest2; + long deffshorter = longest1 < longest2 ? longest1 : longest2; + if (deffLongest >= (deffshorter * 2) - 1 && deffLongest - deffshorter <= 45) { + score += (deffLongest - deffshorter) * 200; + } else if (mainSentiment1 != mainSentiment2 && deffLongest - deffshorter > 20 && deffLongest - deffshorter < 45) { + score += (deffLongest - deffshorter) * 200; } else { - score -= 1424; + score -= (deffLongest - deffshorter) * 50; } } + LevenshteinDistance leven = new LevenshteinDistance(str, str1); + int SentenceScoreDiff = leven.computeLevenshteinDistance(); + SentenceScoreDiff *= 15; + score -= SentenceScoreDiff; + System.out.println("Final current score: " + score + "\nSentence 1: " + str + "\nSentence 2: " + str1 + "\n"); + smxParam.setDistance(score); + } catch (Exception ex) { + System.out.println("ex: " + ex.getMessage() + "\n"); + smxParam.setDistance(-1000); + return smxParam; } - int SentenceScoreDiff = LevenshteinDistance.computeLevenshteinDistance(str, str1); - SentenceScoreDiff *= 15; - // System.out.println("score pre levenhstein substract: " + score + "\nSentenceScoreDiff: " + SentenceScoreDiff + "\n"); - while (SentenceScoreDiff > 0) { - SentenceScoreDiff--; - score--; - } - System.out.println("Final current score: " + score + "\nSentences: " + str + "\n" + str1 + "\n\n\n"); - return score; + return smxParam; } + } diff --git a/ArtificialAutism/src/main/java/PresentationLayer/DiscordHandler.java b/ArtificialAutism/src/main/java/PresentationLayer/DiscordHandler.java index 7900fadc..67851943 100644 --- a/ArtificialAutism/src/main/java/PresentationLayer/DiscordHandler.java +++ b/ArtificialAutism/src/main/java/PresentationLayer/DiscordHandler.java @@ -6,10 +6,9 @@ ps ax | grep EventNotfierDiscordBot-1.0 kill $pid (number) -nohup screen -d -m -S nonRoot java -Xmx5048M -jar /home/Artificial_Autism/ArtificialAutism-1.0.jar -nohup screen -d -m -S nonRoot java -Xmx4048M -jar /home/Artificial_Autism/ArtificialAutism-1.0.jar +nohup screen -d -m -S nonroot java -Xmx6048M -jar /home/javatests/ArtificialAutism-1.0.jar +nohup screen -d -m -S nonroot java -Xmx4048M -jar /home/javatests/ArtificialAutism-1.0.jar -nohup screen -d -m -S gameservers java -Xmx2450M -jar /home/gameservers/ArtificialAutism/ArtificialAutism-1.0.jar screen -ls (number1) screen -X -S (number1) quit */ @@ -20,7 +19,6 @@ package PresentationLayer; import FunctionLayer.CustomError; import FunctionLayer.MYSQLDatahandler; import FunctionLayer.MessageResponseHandler; -import FunctionLayer.StanfordParser.SentimentAnalyzerTest; import java.io.IOException; import java.sql.SQLException; import java.util.List; @@ -37,7 +35,7 @@ import org.javacord.api.entity.user.User; public class DiscordHandler { public static void main(String[] args) { - SentimentAnalyzerTest.shiftReduceParserInitiate(); + MYSQLDatahandler.shiftReduceParserInitiate(); new Thread(() -> { try { MYSQLDatahandler.instance.initiateMYSQL(); @@ -76,8 +74,8 @@ public class DiscordHandler { List userlist = event.getMessage().getMentionedUsers(); String strresult = event.getMessage().toString(); if (userlist != null) { - for (int i = 0; i < userlist.size(); i++) { - strresult = strresult.replace(userlist.get(i).getIdAsString(), ""); + for (User user : userlist) { + strresult = strresult.replace(user.getIdAsString(), ""); } } MessageResponseHandler.getMessage(strresult); @@ -88,14 +86,13 @@ public class DiscordHandler { Logger.getLogger(DiscordHandler.class.getName()).log(Level.SEVERE, null, ex); } } - //contains to specify one channel where bot may always type if (event.getMessage().getMentionedUsers().contains(api.getYourself()) || event.getServerTextChannel().get().toString().contains("minor-test")) { String ResponseStr; try { ResponseStr = MessageResponseHandler.selectReponseMessage(event.getMessage().toString()); if (!ResponseStr.isEmpty()) { - System.out.print("\nResponseStr3: " + ResponseStr); + System.out.print("\nResponseStr3: " + ResponseStr + "\n"); event.getChannel().sendMessage(ResponseStr); } } catch (CustomError ex) { diff --git a/ArtificialAutism/target/ArtificialAutism-1.0.jar b/ArtificialAutism/target/ArtificialAutism-1.0.jar index 2438a3c41e63567262b4db8a080f8d16c842fa3d..4fb774d3284c751395bc7c0a5a15124d6cd41948 100644 GIT binary patch delta 32643 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