package edu.stanford.nlp.sempre.freebase; import edu.stanford.nlp.sempre.freebase.lexicons.TokenLevelMatchFeatures; import edu.stanford.nlp.sempre.*; import edu.stanford.nlp.stats.ClassicCounter; import edu.stanford.nlp.stats.Counter; import edu.stanford.nlp.stats.Counters; import fig.basic.LogInfo; import fig.basic.Option; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * Computes various text-text-similarities * * @author jonathanberant */ public class TextToTextMatcher { public static class Options { @Option(gloss = "Verbose") public int verbose = 0; } public static Options opts = new Options(); private static TextToTextMatcher textToTextMatcher; public static TextToTextMatcher getSingleton() { if (textToTextMatcher == null) textToTextMatcher = new TextToTextMatcher(); return textToTextMatcher; } private Stemmer stemmer; public TextToTextMatcher() { stemmer = new Stemmer(); } public FeatureVector extractFeatures(List<String> exampleTokens, List<String> examplePosTags, List<String> exampleLemmas, Set<String> fbDescs) { FeatureVector res = new FeatureVector(); extractTokenMatchFeatures(exampleTokens, exampleLemmas, fbDescs, res); extractWordSimilarityFeatures(exampleTokens, examplePosTags, fbDescs, res); return res; } // JONATHAN - changing to not have edit distance since it is inefficient private void extractWordSimilarityFeatures(List<String> exampleTokens, List<String> examplePosTags, Set<String> fbDescs, FeatureVector vector) { if (!FeatureExtractor.containsDomain("wordSim")) return; boolean match = false; // collect fb tokens List<String> candidateFbTokens = new ArrayList<>(); for (String fbDesc : fbDescs) { List<String> fbDescTokens = FbFormulasInfo.BinaryFormulaInfo.tokenizeFbDescription(fbDesc); for (String fbDescToken : fbDescTokens) { if (fbDescToken.length() <= 2) continue; candidateFbTokens.add(fbDesc); } } // check if there is a token that is an fb token candidate for (int i = 0; i < exampleTokens.size(); ++i) { String pos = examplePosTags.get(i); String textToken = exampleTokens.get(i); if (pos.startsWith("NN") || (pos.startsWith("VB") && !pos.equals("VBD-AUX")) || pos.equals("JJ")) { if (candidateFbTokens.contains(textToken)) { match = true; break; } } } if (match) vector.add("wordSim", "FbTokenExTokenMatch"); } public boolean existsTokenMatch(List<String> exampleTokens, List<String> exampleLemmas, Set<String> fbDescs) { // generate stems List<String> exampleStems = new ArrayList<String>(); for (String token : exampleTokens) exampleStems.add(stemmer.stem(token)); Counter<String> tokenFeatures = new ClassicCounter<String>(); Counter<String> stemFeatures = new ClassicCounter<String>(); for (String fbDescription : fbDescs) { List<String> fbDescTokens = FbFormulasInfo.BinaryFormulaInfo.tokenizeFbDescription(fbDescription); List<String> fbDescStems = new ArrayList<>(); for (String fbDescToken : fbDescTokens) fbDescStems.add(stemmer.stem(fbDescToken)); Counters.maxInPlace(tokenFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleTokens, fbDescTokens, true)); Counters.maxInPlace(tokenFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleLemmas, fbDescTokens, true)); Counters.maxInPlace(stemFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleStems, fbDescStems, false)); if (tokenFeatures.size() > 0 || stemFeatures.size() > 0) return true; } return false; } private void extractTokenMatchFeatures(List<String> exampleTokens, List<String> exampleLemmas, Set<String> fbDescs, FeatureVector vector) { if (!FeatureExtractor.containsDomain("tokenMatch")) return; // generate stems List<String> exampleStems = new ArrayList<>(); for (String token : exampleTokens) exampleStems.add(stemmer.stem(token)); Counter<String> tokenFeatures = new ClassicCounter<>(); Counter<String> stemFeatures = new ClassicCounter<>(); for (String fbDescription : fbDescs) { List<String> fbDescTokens = FbFormulasInfo.BinaryFormulaInfo.tokenizeFbDescription(fbDescription); List<String> fbDescStems = new ArrayList<>(); for (String fbDescToken : fbDescTokens) fbDescStems.add(stemmer.stem(fbDescToken)); Counters.maxInPlace(tokenFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleTokens, fbDescTokens, true)); Counters.maxInPlace(tokenFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleLemmas, fbDescTokens, true)); Counters.maxInPlace(stemFeatures, TokenLevelMatchFeatures.extractTokenMatchFeatures(exampleStems, fbDescStems, false)); } if (opts.verbose >= 3) { LogInfo.logs("Binary formula desc: %s, token match: %s, stem match: %s", fbDescs, tokenFeatures, stemFeatures); } addFeaturesToVector(tokenFeatures, "binary_token", vector); addFeaturesToVector(stemFeatures, "binary_stem", vector); } private void addFeaturesToVector(Counter<String> features, String prefix, FeatureVector vector) { if (features.getCount("equal") > 0) vector.add("tokenMatch", prefix + ".equal", features.getCount("equal")); else if (features.getCount("prefix") > 0 || features.getCount("suffix") > 0) { if (features.getCount("prefix") > 0) vector.add("tokenMatch", prefix + ".prefix", features.getCount("prefix")); if (features.getCount("suffix") > 0) vector.add("tokenMatch", prefix + ".suffix", features.getCount("suffix")); } else if (features.getCount("overlap") > 0) vector.add("tokenMatch", prefix + ".overlap", features.getCount("overlap")); } }