forked from D-Net/dnet-hadoop
Added first implementation using UDF function
This commit is contained in:
parent
9963fd6d29
commit
4c2dfcbdf7
|
@ -143,8 +143,8 @@
|
|||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib</groupId>
|
||||
<artifactId>dnet-pace-core</artifactId>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dhp-pace-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dhp</artifactId>
|
||||
<version>1.2.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dhp-pace-core</artifactId>
|
||||
<version>1.2.5-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>edu.cmu</groupId>
|
||||
<artifactId>secondstring</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>stringtemplate</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>stringtemplate</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.spark</groupId>
|
||||
<artifactId>spark-catalyst_2.11</artifactId>
|
||||
<version>2.4.0.cloudera2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,42 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class AbstractClusteringFunction extends AbstractPaceFunctions implements ClusteringFunction {
|
||||
|
||||
protected Map<String, Integer> params;
|
||||
|
||||
public AbstractClusteringFunction(final Map<String, Integer> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
protected abstract Collection<String> doApply(Config conf, String s);
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(Config conf, List<String> fields) {
|
||||
return fields.stream().filter(f -> !f.isEmpty())
|
||||
.map(this::normalize)
|
||||
.map(s -> filterAllStopWords(s))
|
||||
.map(s -> doApply(conf, s))
|
||||
.map(c -> filterBlacklisted(c, ngramBlacklist))
|
||||
.flatMap(c -> c.stream())
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
}
|
||||
|
||||
public Map<String, Integer> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
protected Integer param(String name) {
|
||||
return params.get(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("acronyms")
|
||||
public class Acronyms extends AbstractClusteringFunction {
|
||||
|
||||
public Acronyms(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return extractAcronyms(s, param("max"), param("minLen"), param("maxLen"));
|
||||
}
|
||||
|
||||
private Set<String> extractAcronyms(final String s, int maxAcronyms, int minLen, int maxLen) {
|
||||
|
||||
final Set<String> acronyms = Sets.newLinkedHashSet();
|
||||
|
||||
for (int i = 0; i < maxAcronyms; i++) {
|
||||
|
||||
final StringTokenizer st = new StringTokenizer(s);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
final String token = st.nextToken();
|
||||
if (sb.length() > maxLen) {
|
||||
break;
|
||||
}
|
||||
if (token.length() > 1 && i < token.length()) {
|
||||
sb.append(token.charAt(i));
|
||||
}
|
||||
}
|
||||
String acronym = sb.toString();
|
||||
if (acronym.length() > minLen) {
|
||||
acronyms.add(acronym);
|
||||
}
|
||||
}
|
||||
return acronyms;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ClusteringClass {
|
||||
|
||||
public String value();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ClusteringFunction {
|
||||
|
||||
public Collection<String> apply(Config config, List<String> fields);
|
||||
|
||||
public Map<String, Integer> getParams();
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("immutablefieldvalue")
|
||||
public class ImmutableFieldValue extends AbstractClusteringFunction {
|
||||
|
||||
public ImmutableFieldValue(final Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, final String s) {
|
||||
final List<String> res = Lists.newArrayList();
|
||||
|
||||
res.add(s);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ClusteringClass("keywordsclustering")
|
||||
public class KeywordsClustering extends AbstractClusteringFunction {
|
||||
|
||||
public KeywordsClustering(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, String s) {
|
||||
|
||||
//takes city codes and keywords codes without duplicates
|
||||
Set<String> keywords = getKeywords(s, conf.translationMap(), params.getOrDefault("windowSize", 4));
|
||||
Set<String> cities = getCities(s, params.getOrDefault("windowSize", 4));
|
||||
|
||||
//list of combination to return as result
|
||||
final Collection<String> combinations = new LinkedHashSet<String>();
|
||||
|
||||
for (String keyword: keywordsToCodes(keywords, conf.translationMap())){
|
||||
for (String city: citiesToCodes(cities)) {
|
||||
combinations.add(keyword+"-"+city);
|
||||
if (combinations.size()>=params.getOrDefault("max", 2)) {
|
||||
return combinations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combinations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(final Config conf, List<String> fields) {
|
||||
return fields.stream().filter(f -> !f.isEmpty())
|
||||
.map(this::cleanup)
|
||||
.map(this::normalize)
|
||||
.map(s -> filterAllStopWords(s))
|
||||
.map(s -> doApply(conf, s))
|
||||
.map(c -> filterBlacklisted(c, ngramBlacklist))
|
||||
.flatMap(c -> c.stream())
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.model.Person;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ClusteringClass("lnfi")
|
||||
public class LastNameFirstInitial extends AbstractClusteringFunction{
|
||||
|
||||
private boolean DEFAULT_AGGRESSIVE = true;
|
||||
|
||||
public LastNameFirstInitial(final Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(Config conf, List<String> fields) {
|
||||
return fields.stream().filter(f -> !f.isEmpty())
|
||||
.map(this::normalize)
|
||||
.map(s -> doApply(conf, s))
|
||||
.map(c -> filterBlacklisted(c, ngramBlacklist))
|
||||
.flatMap(c -> c.stream())
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalize(final String s) {
|
||||
return fixAliases(transliterate(nfd(unicodeNormalization(s))))
|
||||
// do not compact the regexes in a single expression, would cause StackOverflowError in case of large input strings
|
||||
.replaceAll("[^ \\w]+", "")
|
||||
.replaceAll("(\\p{InCombiningDiacriticalMarks})+", "")
|
||||
.replaceAll("(\\p{Punct})+", " ")
|
||||
.replaceAll("(\\d)+", " ")
|
||||
.replaceAll("(\\n)+", " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, final String s) {
|
||||
|
||||
final List<String> res = Lists.newArrayList();
|
||||
|
||||
final boolean aggressive = (Boolean) (getParams().containsKey("aggressive") ? getParams().get("aggressive") : DEFAULT_AGGRESSIVE);
|
||||
|
||||
Person p = new Person(s, aggressive);
|
||||
|
||||
if (p.isAccurate()) {
|
||||
String lastName = p.getNormalisedSurname().toLowerCase();
|
||||
String firstInitial = p.getNormalisedFirstName().toLowerCase().substring(0,1);
|
||||
|
||||
res.add(firstInitial.concat(lastName));
|
||||
}
|
||||
else { // is not accurate, meaning it has no defined name and surname
|
||||
List<String> fullname = Arrays.asList(p.getNormalisedFullname().split(" "));
|
||||
if (fullname.size() == 1) {
|
||||
res.add(p.getNormalisedFullname().toLowerCase());
|
||||
}
|
||||
else if (fullname.size() == 2) {
|
||||
res.add(fullname.get(0).substring(0,1).concat(fullname.get(1)).toLowerCase());
|
||||
res.add(fullname.get(1).substring(0,1).concat(fullname.get(0)).toLowerCase());
|
||||
}
|
||||
else {
|
||||
res.add(fullname.get(0).substring(0,1).concat(fullname.get(fullname.size()-1)).toLowerCase());
|
||||
res.add(fullname.get(fullname.size()-1).substring(0,1).concat(fullname.get(0)).toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ClusteringClass("lowercase")
|
||||
public class LowercaseClustering extends AbstractClusteringFunction {
|
||||
|
||||
public LowercaseClustering(final Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(Config conf, List<String> fields) {
|
||||
Collection<String> c = Sets.newLinkedHashSet();
|
||||
for(String f : fields) {
|
||||
c.addAll(doApply(conf, f));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, final String s) {
|
||||
if(StringUtils.isBlank(s)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return Lists.newArrayList(s.toLowerCase().trim());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
|
||||
public class NGramUtils extends AbstractPaceFunctions {
|
||||
static private final NGramUtils NGRAMUTILS = new NGramUtils();
|
||||
|
||||
private static final int SIZE = 100;
|
||||
|
||||
private static final Set<String> stopwords = AbstractPaceFunctions.loadFromClasspath("/eu/dnetlib/pace/config/stopwords_en.txt");
|
||||
|
||||
public static String cleanupForOrdering(String s) {
|
||||
String result = NGRAMUTILS.filterStopWords(NGRAMUTILS.normalize(s), stopwords);
|
||||
return result.isEmpty() ? result : result.replace(" ", "");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("ngrampairs")
|
||||
public class NgramPairs extends Ngrams {
|
||||
|
||||
public NgramPairs(Map<String, Integer> params) {
|
||||
super(params, false);
|
||||
}
|
||||
|
||||
public NgramPairs(Map<String, Integer> params, boolean sorted) {
|
||||
super(params, sorted);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return ngramPairs(Lists.newArrayList(getNgrams(s, param("ngramLen"), param("max") * 2, 1, 2)), param("max"));
|
||||
}
|
||||
|
||||
protected Collection<String> ngramPairs(final List<String> ngrams, int maxNgrams) {
|
||||
Collection<String> res = Lists.newArrayList();
|
||||
int j = 0;
|
||||
for (int i = 0; i < ngrams.size() && res.size() < maxNgrams; i++) {
|
||||
if (++j >= ngrams.size()) {
|
||||
break;
|
||||
}
|
||||
res.add(ngrams.get(i) + ngrams.get(j));
|
||||
//System.out.println("-- " + concatNgrams);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ClusteringClass("ngrams")
|
||||
public class Ngrams extends AbstractClusteringFunction {
|
||||
|
||||
private final boolean sorted;
|
||||
|
||||
public Ngrams(Map<String, Integer> params) {
|
||||
this(params, false);
|
||||
}
|
||||
|
||||
public Ngrams(Map<String, Integer> params, boolean sorted) {
|
||||
super(params);
|
||||
this.sorted = sorted;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return getNgrams(s, param("ngramLen"), param("max"), param("maxPerToken"), param("minNgramLen"));
|
||||
}
|
||||
|
||||
protected Collection<String> getNgrams(String s, int ngramLen, int max, int maxPerToken, int minNgramLen) {
|
||||
|
||||
final Collection<String> ngrams = sorted ? new TreeSet<>() : new LinkedHashSet<String>();
|
||||
final StringTokenizer st = new StringTokenizer(s);
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
final String token = st.nextToken();
|
||||
if (!token.isEmpty()) {
|
||||
for (int i = 0; i < maxPerToken && ngramLen + i <= token.length(); i++) {
|
||||
String ngram = token.substring(i, Math.min(ngramLen + i, token.length())).trim();
|
||||
|
||||
if (ngram.length() >= minNgramLen) {
|
||||
ngrams.add(ngram);
|
||||
|
||||
if (ngrams.size() >= max) {
|
||||
return ngrams;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//System.out.println(ngrams + " n: " + ngrams.size());
|
||||
return ngrams;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.model.Person;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ClusteringClass("personClustering")
|
||||
public class PersonClustering extends AbstractPaceFunctions implements ClusteringFunction {
|
||||
|
||||
private Map<String, Integer> params;
|
||||
|
||||
private static final int MAX_TOKENS = 5;
|
||||
|
||||
public PersonClustering(final Map<String, Integer> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(final Config conf, final List<String> fields) {
|
||||
final Set<String> hashes = Sets.newHashSet();
|
||||
|
||||
for (final String f : fields) {
|
||||
|
||||
final Person person = new Person(f, false);
|
||||
|
||||
if (StringUtils.isNotBlank(person.getNormalisedFirstName()) && StringUtils.isNotBlank(person.getNormalisedSurname())) {
|
||||
hashes.add(firstLC(person.getNormalisedFirstName()) + person.getNormalisedSurname().toLowerCase());
|
||||
} else {
|
||||
for (final String token1 : tokens(f, MAX_TOKENS)) {
|
||||
for (final String token2 : tokens(f, MAX_TOKENS)) {
|
||||
if (!token1.equals(token2)) {
|
||||
hashes.add(firstLC(token1) + token2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public Collection<String> apply(final List<Field> fields) {
|
||||
// final Set<String> hashes = Sets.newHashSet();
|
||||
//
|
||||
// for (final Field f : fields) {
|
||||
//
|
||||
// final GTAuthor gta = GTAuthor.fromOafJson(f.stringValue());
|
||||
//
|
||||
// final Author a = gta.getAuthor();
|
||||
//
|
||||
// if (StringUtils.isNotBlank(a.getFirstname()) && StringUtils.isNotBlank(a.getSecondnames())) {
|
||||
// hashes.add(firstLC(a.getFirstname()) + a.getSecondnames().toLowerCase());
|
||||
// } else {
|
||||
// for (final String token1 : tokens(f.stringValue(), MAX_TOKENS)) {
|
||||
// for (final String token2 : tokens(f.stringValue(), MAX_TOKENS)) {
|
||||
// if (!token1.equals(token2)) {
|
||||
// hashes.add(firstLC(token1) + token2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return hashes;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.model.Person;
|
||||
|
||||
@ClusteringClass("personHash")
|
||||
public class PersonHash extends AbstractClusteringFunction {
|
||||
|
||||
private boolean DEFAULT_AGGRESSIVE = false;
|
||||
|
||||
public PersonHash(final Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, final String s) {
|
||||
final List<String> res = Lists.newArrayList();
|
||||
|
||||
final boolean aggressive = (Boolean) (getParams().containsKey("aggressive") ? getParams().get("aggressive") : DEFAULT_AGGRESSIVE);
|
||||
|
||||
res.add(new Person(s, aggressive).hash());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class RandomClusteringFunction extends AbstractClusteringFunction {
|
||||
|
||||
public RandomClusteringFunction(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("sortedngrampairs")
|
||||
public class SortedNgramPairs extends NgramPairs {
|
||||
|
||||
public SortedNgramPairs(Map<String, Integer> params) {
|
||||
super(params, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@ClusteringClass("spacetrimmingfieldvalue")
|
||||
public class SpaceTrimmingFieldValue extends AbstractClusteringFunction {
|
||||
|
||||
public SpaceTrimmingFieldValue(final Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(final Config conf, final String s) {
|
||||
final List<String> res = Lists.newArrayList();
|
||||
|
||||
res.add(StringUtils.isBlank(s) ? RandomStringUtils.random(getParams().get("randomLength")) : s.toLowerCase().replaceAll("\\s+", ""));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("suffixprefix")
|
||||
public class SuffixPrefix extends AbstractClusteringFunction {
|
||||
|
||||
public SuffixPrefix(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return suffixPrefix(s, param("len"), param("max"));
|
||||
}
|
||||
|
||||
private Collection<String> suffixPrefix(String s, int len, int max) {
|
||||
final Set<String> bigrams = Sets.newLinkedHashSet();
|
||||
int i = 0;
|
||||
while (++i < s.length() && bigrams.size() < max) {
|
||||
int j = s.indexOf(" ", i);
|
||||
|
||||
int offset = j + len + 1 < s.length() ? j + len + 1 : s.length();
|
||||
|
||||
if (j - len > 0) {
|
||||
String bigram = s.substring(j - len, offset).replaceAll(" ", "").trim();
|
||||
if (bigram.length() >= 4) {
|
||||
bigrams.add(bigram);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bigrams;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ClusteringClass("urlclustering")
|
||||
public class UrlClustering extends AbstractPaceFunctions implements ClusteringFunction {
|
||||
|
||||
protected Map<String, Integer> params;
|
||||
|
||||
public UrlClustering(final Map<String, Integer> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> apply(final Config conf, List<String> fields) {
|
||||
try {
|
||||
return fields.stream()
|
||||
.filter(f -> !f.isEmpty())
|
||||
.map(this::asUrl)
|
||||
.map(URL::getHost)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
}
|
||||
catch (IllegalStateException e){
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> getParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private URL asUrl(String value) {
|
||||
try {
|
||||
return new URL(value);
|
||||
} catch (MalformedURLException e) {
|
||||
// should not happen as checked by pace typing
|
||||
throw new IllegalStateException("invalid URL: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ClusteringClass("wordsStatsSuffixPrefixChain")
|
||||
public class WordsStatsSuffixPrefixChain extends AbstractClusteringFunction {
|
||||
|
||||
public WordsStatsSuffixPrefixChain(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return suffixPrefixChain(s, param("mod"));
|
||||
}
|
||||
|
||||
private Collection<String> suffixPrefixChain(String s, int mod) {
|
||||
|
||||
//create the list of words from the string (remove short words)
|
||||
List<String> wordsList =
|
||||
Arrays.stream(s.split(" "))
|
||||
.filter(si -> si.length() > 3)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final int words = wordsList.size();
|
||||
final int letters = s.length();
|
||||
|
||||
//create the prefix: number of words + number of letters/mod
|
||||
String prefix = words + "-" + letters/mod + "-";
|
||||
|
||||
return doSuffixPrefixChain(wordsList, prefix);
|
||||
|
||||
}
|
||||
|
||||
private Collection<String> doSuffixPrefixChain(List<String> wordsList, String prefix) {
|
||||
|
||||
Set<String> set = Sets.newLinkedHashSet();
|
||||
switch(wordsList.size()){
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
set.add(
|
||||
prefix +
|
||||
suffix(wordsList.get(0), 3) +
|
||||
prefix(wordsList.get(1), 3)
|
||||
);
|
||||
|
||||
set.add(
|
||||
prefix +
|
||||
prefix(wordsList.get(0), 3) +
|
||||
suffix(wordsList.get(1), 3)
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
set.add(
|
||||
prefix +
|
||||
suffix(wordsList.get(0), 3) +
|
||||
prefix(wordsList.get(1), 3) +
|
||||
suffix(wordsList.get(2), 3)
|
||||
);
|
||||
|
||||
set.add(
|
||||
prefix +
|
||||
prefix(wordsList.get(0), 3) +
|
||||
suffix(wordsList.get(1), 3) +
|
||||
prefix(wordsList.get(2), 3)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return set;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private String suffix(String s, int len) {
|
||||
return s.substring(s.length()-len);
|
||||
}
|
||||
|
||||
private String prefix(String s, int len) {
|
||||
return s.substring(0, len);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package eu.dnetlib.pace.clustering;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
@ClusteringClass("wordssuffixprefix")
|
||||
public class WordsSuffixPrefix extends AbstractClusteringFunction {
|
||||
|
||||
public WordsSuffixPrefix(Map<String, Integer> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> doApply(Config conf, String s) {
|
||||
return suffixPrefix(s, param("len"), param("max"));
|
||||
}
|
||||
|
||||
private Collection<String> suffixPrefix(String s, int len, int max) {
|
||||
|
||||
final int words = s.split(" ").length;
|
||||
|
||||
// adjust the token length according to the number of words
|
||||
switch (words) {
|
||||
case 1:
|
||||
return Sets.newLinkedHashSet();
|
||||
case 2:
|
||||
return doSuffixPrefix(s, len+2, max, words);
|
||||
case 3:
|
||||
return doSuffixPrefix(s, len+1, max, words);
|
||||
default:
|
||||
return doSuffixPrefix(s, len, max, words);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> doSuffixPrefix(String s, int len, int max, int words) {
|
||||
final Set<String> bigrams = Sets.newLinkedHashSet();
|
||||
int i = 0;
|
||||
while (++i < s.length() && bigrams.size() < max) {
|
||||
int j = s.indexOf(" ", i);
|
||||
|
||||
int offset = j + len + 1 < s.length() ? j + len + 1 : s.length();
|
||||
|
||||
if (j - len > 0) {
|
||||
String bigram = s.substring(j - len, offset).replaceAll(" ", "").trim();
|
||||
if (bigram.length() >= 4) {
|
||||
bigrams.add(words+bigram);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bigrams;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
package eu.dnetlib.pace.common;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.ibm.icu.text.Transliterator;
|
||||
import eu.dnetlib.pace.clustering.NGramUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.Normalizer;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Set of common functions for the framework
|
||||
*
|
||||
* @author claudio
|
||||
*/
|
||||
public abstract class AbstractPaceFunctions {
|
||||
|
||||
//city map to be used when translating the city names into codes
|
||||
private static Map<String, String> cityMap = AbstractPaceFunctions.loadMapFromClasspath("/eu/dnetlib/pace/config/city_map.csv");
|
||||
|
||||
//list of stopwords in different languages
|
||||
protected static Set<String> stopwords_gr = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_gr.txt");
|
||||
protected static Set<String> stopwords_en = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_en.txt");
|
||||
protected static Set<String> stopwords_de = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_de.txt");
|
||||
protected static Set<String> stopwords_es = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_es.txt");
|
||||
protected static Set<String> stopwords_fr = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_fr.txt");
|
||||
protected static Set<String> stopwords_it = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_it.txt");
|
||||
protected static Set<String> stopwords_pt = loadFromClasspath("/eu/dnetlib/pace/config/stopwords_pt.txt");
|
||||
|
||||
//transliterator
|
||||
protected static Transliterator transliterator = Transliterator.getInstance("Any-Eng");
|
||||
|
||||
//blacklist of ngrams: to avoid generic keys
|
||||
protected static Set<String> ngramBlacklist = loadFromClasspath("/eu/dnetlib/pace/config/ngram_blacklist.txt");
|
||||
|
||||
//html regex for normalization
|
||||
public final String HTML_REGEX = "<[^>]*>";
|
||||
|
||||
private static final String alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
|
||||
private static final String aliases_from = "⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎àáâäæãåāèéêëēėęəîïíīįìôöòóœøōõûüùúūßśšłžźżçćčñń";
|
||||
private static final String aliases_to = "0123456789+-=()n0123456789+-=()aaaaaaaaeeeeeeeeiiiiiioooooooouuuuussslzzzcccnn";
|
||||
|
||||
//doi prefix for normalization
|
||||
public final String DOI_PREFIX = "(https?:\\/\\/dx\\.doi\\.org\\/)|(doi:)";
|
||||
|
||||
private Pattern numberPattern = Pattern.compile("-?\\d+(\\.\\d+)?");
|
||||
|
||||
private Pattern hexUnicodePattern = Pattern.compile("\\\\u(\\p{XDigit}{4})");
|
||||
|
||||
protected String concat(final List<String> l) {
|
||||
return Joiner.on(" ").skipNulls().join(l);
|
||||
}
|
||||
|
||||
protected String cleanup(final String s) {
|
||||
|
||||
final String s1 = s.replaceAll(HTML_REGEX, "");
|
||||
final String s2 = unicodeNormalization(s1.toLowerCase());
|
||||
final String s3 = nfd(s2);
|
||||
final String s4 = fixXML(s3);
|
||||
final String s5 = s4.replaceAll("([0-9]+)", " $1 ");
|
||||
final String s6 = transliterate(s5);
|
||||
final String s7 = fixAliases(s6);
|
||||
final String s8 = s7.replaceAll("[^\\p{ASCII}]", "");
|
||||
final String s9 = s8.replaceAll("[\\p{Punct}]", " ");
|
||||
final String s10 = s9.replaceAll("\\n", " ");
|
||||
final String s11 = s10.replaceAll("(?m)\\s+", " ");
|
||||
final String s12 = s11.trim();
|
||||
return s12;
|
||||
}
|
||||
|
||||
protected String fixXML(final String a){
|
||||
|
||||
return a.replaceAll("–", " ")
|
||||
.replaceAll("&", " ")
|
||||
.replaceAll(""", " ")
|
||||
.replaceAll("−", " ");
|
||||
}
|
||||
|
||||
protected boolean checkNumbers(final String a, final String b) {
|
||||
final String numbersA = getNumbers(a);
|
||||
final String numbersB = getNumbers(b);
|
||||
final String romansA = getRomans(a);
|
||||
final String romansB = getRomans(b);
|
||||
return !numbersA.equals(numbersB) || !romansA.equals(romansB);
|
||||
}
|
||||
|
||||
protected String getRomans(final String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final String t : s.split(" ")) {
|
||||
sb.append(isRoman(t) ? t : "");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected boolean isRoman(final String s) {
|
||||
return s.replaceAll("^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", "qwertyuiop").equals("qwertyuiop");
|
||||
}
|
||||
|
||||
protected String getNumbers(final String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final String t : s.split(" ")) {
|
||||
sb.append(isNumber(t) ? t : "");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isNumber(String strNum) {
|
||||
if (strNum == null) {
|
||||
return false;
|
||||
}
|
||||
return numberPattern.matcher(strNum).matches();
|
||||
}
|
||||
|
||||
protected static String fixAliases(final String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final char ch : Lists.charactersOf(s)) {
|
||||
final int i = StringUtils.indexOf(aliases_from, ch);
|
||||
sb.append(i >= 0 ? aliases_to.charAt(i) : ch);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected static String transliterate(final String s) {
|
||||
try {
|
||||
return transliterator.transliterate(s);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
protected String removeSymbols(final String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final char ch : Lists.charactersOf(s)) {
|
||||
sb.append(StringUtils.contains(alpha, ch) ? ch : " ");
|
||||
}
|
||||
return sb.toString().replaceAll("\\s+", " ");
|
||||
}
|
||||
|
||||
protected boolean notNull(final String s) {
|
||||
return s != null;
|
||||
}
|
||||
|
||||
protected String normalize(final String s) {
|
||||
return fixAliases(transliterate(nfd(unicodeNormalization(s))))
|
||||
.toLowerCase()
|
||||
// do not compact the regexes in a single expression, would cause StackOverflowError in case of large input strings
|
||||
.replaceAll("[^ \\w]+", "")
|
||||
.replaceAll("(\\p{InCombiningDiacriticalMarks})+", "")
|
||||
.replaceAll("(\\p{Punct})+", " ")
|
||||
.replaceAll("(\\d)+", " ")
|
||||
.replaceAll("(\\n)+", " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
public String nfd(final String s) {
|
||||
return Normalizer.normalize(s, Normalizer.Form.NFD);
|
||||
}
|
||||
|
||||
public String utf8(final String s) {
|
||||
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public String unicodeNormalization(final String s) {
|
||||
|
||||
Matcher m = hexUnicodePattern.matcher(s);
|
||||
StringBuffer buf = new StringBuffer(s.length());
|
||||
while (m.find()) {
|
||||
String ch = String.valueOf((char) Integer.parseInt(m.group(1), 16));
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(ch));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String filterStopWords(final String s, final Set<String> stopwords) {
|
||||
final StringTokenizer st = new StringTokenizer(s);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
while (st.hasMoreTokens()) {
|
||||
final String token = st.nextToken();
|
||||
if (!stopwords.contains(token)) {
|
||||
sb.append(token);
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public String filterAllStopWords(String s) {
|
||||
|
||||
s = filterStopWords(s, stopwords_en);
|
||||
s = filterStopWords(s, stopwords_de);
|
||||
s = filterStopWords(s, stopwords_it);
|
||||
s = filterStopWords(s, stopwords_fr);
|
||||
s = filterStopWords(s, stopwords_pt);
|
||||
s = filterStopWords(s, stopwords_es);
|
||||
s = filterStopWords(s, stopwords_gr);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
protected Collection<String> filterBlacklisted(final Collection<String> set, final Set<String> ngramBlacklist) {
|
||||
final Set<String> newset = Sets.newLinkedHashSet();
|
||||
for (final String s : set) {
|
||||
if (!ngramBlacklist.contains(s)) {
|
||||
newset.add(s);
|
||||
}
|
||||
}
|
||||
return newset;
|
||||
}
|
||||
|
||||
public static Set<String> loadFromClasspath(final String classpath) {
|
||||
|
||||
Transliterator transliterator = Transliterator.getInstance("Any-Eng");
|
||||
|
||||
final Set<String> h = Sets.newHashSet();
|
||||
try {
|
||||
for (final String s : IOUtils.readLines(NGramUtils.class.getResourceAsStream(classpath))) {
|
||||
h.add(fixAliases(transliterator.transliterate(s))); //transliteration of the stopwords
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public static Map<String, String> loadMapFromClasspath(final String classpath) {
|
||||
|
||||
Transliterator transliterator = Transliterator.getInstance("Any-Eng");
|
||||
|
||||
final Map<String, String> m = new HashMap<>();
|
||||
try {
|
||||
for (final String s : IOUtils.readLines(AbstractPaceFunctions.class.getResourceAsStream(classpath))) {
|
||||
//string is like this: code;word1;word2;word3
|
||||
String[] line = s.split(";");
|
||||
String value = line[0];
|
||||
for (int i = 1; i < line.length; i++) {
|
||||
m.put(fixAliases(transliterator.transliterate(line[i].toLowerCase())), value);
|
||||
}
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public String removeKeywords(String s, Set<String> keywords) {
|
||||
|
||||
s = " " + s + " ";
|
||||
for (String k : keywords) {
|
||||
s = s.replaceAll(k.toLowerCase(), "");
|
||||
}
|
||||
|
||||
return s.trim();
|
||||
}
|
||||
|
||||
public double commonElementsPercentage(Set<String> s1, Set<String> s2) {
|
||||
|
||||
double longer = Math.max(s1.size(), s2.size());
|
||||
return (double) s1.stream().filter(s2::contains).count() / longer;
|
||||
}
|
||||
|
||||
//convert the set of keywords to codes
|
||||
public Set<String> toCodes(Set<String> keywords, Map<String, String> translationMap) {
|
||||
return keywords.stream().map(s -> translationMap.get(s)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<String> keywordsToCodes(Set<String> keywords, Map<String, String> translationMap) {
|
||||
return toCodes(keywords, translationMap);
|
||||
}
|
||||
|
||||
public Set<String> citiesToCodes(Set<String> keywords) {
|
||||
return toCodes(keywords, cityMap);
|
||||
}
|
||||
|
||||
protected String firstLC(final String s) {
|
||||
return StringUtils.substring(s, 0, 1).toLowerCase();
|
||||
}
|
||||
|
||||
protected Iterable<String> tokens(final String s, final int maxTokens) {
|
||||
return Iterables.limit(Splitter.on(" ").omitEmptyStrings().trimResults().split(s), maxTokens);
|
||||
}
|
||||
|
||||
public String normalizePid(String pid) {
|
||||
return pid.toLowerCase().replaceAll(DOI_PREFIX, "");
|
||||
}
|
||||
|
||||
//get the list of keywords into the input string
|
||||
public Set<String> getKeywords(String s1, Map<String, String> translationMap, int windowSize) {
|
||||
|
||||
String s = s1;
|
||||
|
||||
List<String> tokens = Arrays.asList(s.toLowerCase().split(" "));
|
||||
|
||||
Set<String> codes = new HashSet<>();
|
||||
|
||||
if (tokens.size() < windowSize)
|
||||
windowSize = tokens.size();
|
||||
|
||||
int length = windowSize;
|
||||
|
||||
while (length != 0) {
|
||||
|
||||
for (int i = 0; i <= tokens.size() - length; i++) {
|
||||
String candidate = concat(tokens.subList(i, i + length));
|
||||
if (translationMap.containsKey(candidate)) {
|
||||
codes.add(candidate);
|
||||
s = s.replace(candidate, "").trim();
|
||||
}
|
||||
}
|
||||
|
||||
tokens = Arrays.asList(s.split(" "));
|
||||
length -= 1;
|
||||
}
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
public Set<String> getCities(String s1, int windowSize) {
|
||||
return getKeywords(s1, cityMap, windowSize);
|
||||
}
|
||||
|
||||
public static <T> String readFromClasspath(final String filename, final Class<T> clazz) {
|
||||
final StringWriter sw = new StringWriter();
|
||||
try {
|
||||
IOUtils.copy(clazz.getResourceAsStream(filename), sw);
|
||||
return sw.toString();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException("cannot load resource from classpath: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package eu.dnetlib.pace.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import eu.dnetlib.pace.model.ClusteringDef;
|
||||
import eu.dnetlib.pace.model.FieldDef;
|
||||
import eu.dnetlib.pace.tree.support.TreeNodeDef;
|
||||
|
||||
/**
|
||||
* Interface for PACE configuration bean.
|
||||
*
|
||||
* @author claudio
|
||||
*/
|
||||
public interface Config {
|
||||
|
||||
/**
|
||||
* Field configuration definitions.
|
||||
*
|
||||
* @return the list of definitions
|
||||
*/
|
||||
public List<FieldDef> model();
|
||||
|
||||
/**
|
||||
* Decision Tree definition
|
||||
*
|
||||
* @return the map representing the decision tree
|
||||
*/
|
||||
public Map<String, TreeNodeDef> decisionTree();
|
||||
|
||||
/**
|
||||
* Clusterings.
|
||||
*
|
||||
* @return the list
|
||||
*/
|
||||
public List<ClusteringDef> clusterings();
|
||||
|
||||
/**
|
||||
* Blacklists.
|
||||
*
|
||||
* @return the map
|
||||
*/
|
||||
public Map<String, Predicate<String>> blacklists();
|
||||
|
||||
|
||||
/**
|
||||
* Translation map.
|
||||
*
|
||||
* @return the map
|
||||
* */
|
||||
public Map<String, String> translationMap();
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package eu.dnetlib.pace.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Maps;
|
||||
import eu.dnetlib.pace.model.ClusteringDef;
|
||||
import eu.dnetlib.pace.model.FieldDef;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
import eu.dnetlib.pace.tree.support.TreeNodeDef;
|
||||
|
||||
|
||||
public class DedupConfig implements Config, Serializable {
|
||||
private static String CONFIG_TEMPLATE = "dedupConfig.st";
|
||||
|
||||
private PaceConfig pace;
|
||||
|
||||
private WfConfig wf;
|
||||
|
||||
@JsonIgnore
|
||||
private Map<String, Predicate<String>> blacklists;
|
||||
|
||||
private static Map<String, String> defaults = Maps.newHashMap();
|
||||
|
||||
static {
|
||||
defaults.put("dedupRun", "001");
|
||||
defaults.put("entityType", "result");
|
||||
defaults.put("subEntityType", "resulttype");
|
||||
defaults.put("subEntityValue", "publication");
|
||||
defaults.put("orderField", "title");
|
||||
defaults.put("queueMaxSize", "2000");
|
||||
defaults.put("groupMaxSize", "10");
|
||||
defaults.put("slidingWindowSize", "200");
|
||||
defaults.put("rootBuilder", "result");
|
||||
defaults.put("includeChildren", "true");
|
||||
defaults.put("maxIterations", "20");
|
||||
defaults.put("idPath", "$.id");
|
||||
}
|
||||
|
||||
public DedupConfig() {
|
||||
}
|
||||
|
||||
public static DedupConfig load(final String json) {
|
||||
|
||||
final DedupConfig config;
|
||||
try {
|
||||
config = new ObjectMapper().readValue(json, DedupConfig.class);
|
||||
config.getPace().initModel();
|
||||
config.getPace().initTranslationMap();
|
||||
|
||||
config.blacklists = config.getPace().getBlacklists().entrySet()
|
||||
.stream()
|
||||
.map(e -> new AbstractMap.SimpleEntry<String, List<Pattern>>(e.getKey(), e.getValue().stream().filter(s -> !StringUtils.isBlank(s)).map(Pattern::compile).collect(Collectors.toList())))
|
||||
.collect(Collectors.toMap(e -> e.getKey(),
|
||||
e -> (Predicate<String> & Serializable) s -> e.getValue().stream().filter(p -> p.matcher(s).matches()).findFirst().isPresent()))
|
||||
|
||||
;
|
||||
|
||||
return config;
|
||||
} catch (IOException |
|
||||
PatternSyntaxException e) {
|
||||
throw new PaceException("Error in parsing configuration json", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static DedupConfig loadDefault() throws IOException {
|
||||
return loadDefault(new HashMap<String, String>());
|
||||
}
|
||||
|
||||
public static DedupConfig loadDefault(final Map<String, String> params) throws IOException {
|
||||
|
||||
final StringTemplate template = new StringTemplate(new DedupConfig().readFromClasspath(CONFIG_TEMPLATE));
|
||||
|
||||
for (final Entry<String, String> e : defaults.entrySet()) {
|
||||
template.setAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
for (final Entry<String, String> e : params.entrySet()) {
|
||||
if (template.getAttribute(e.getKey()) != null) {
|
||||
template.getAttributes().computeIfPresent(e.getKey(), (o, o2) -> e.getValue());
|
||||
} else {
|
||||
template.setAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
final String json = template.toString();
|
||||
return load(json);
|
||||
}
|
||||
|
||||
private String readFromClasspath(final String resource) throws IOException {
|
||||
return IOUtils.toString(getClass().getResource(resource), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public PaceConfig getPace() {
|
||||
return pace;
|
||||
}
|
||||
|
||||
public void setPace(final PaceConfig pace) {
|
||||
this.pace = pace;
|
||||
}
|
||||
|
||||
public WfConfig getWf() {
|
||||
return wf;
|
||||
}
|
||||
|
||||
public void setWf(final WfConfig wf) {
|
||||
this.wf = wf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("unable to serialise configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TreeNodeDef> decisionTree() {
|
||||
return getPace().getDecisionTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FieldDef> model() {
|
||||
return getPace().getModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClusteringDef> clusterings() {
|
||||
return getPace().getClustering();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Predicate<String>> blacklists() {
|
||||
return blacklists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> translationMap() {
|
||||
return getPace().translationMap();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package eu.dnetlib.pace.config;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.ibm.icu.text.Transliterator;
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.model.ClusteringDef;
|
||||
import eu.dnetlib.pace.model.FieldDef;
|
||||
import eu.dnetlib.pace.tree.support.TreeNodeDef;
|
||||
import eu.dnetlib.pace.util.PaceResolver;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PaceConfig extends AbstractPaceFunctions implements Serializable {
|
||||
|
||||
private List<FieldDef> model;
|
||||
|
||||
private List<ClusteringDef> clustering;
|
||||
private Map<String, TreeNodeDef> decisionTree;
|
||||
|
||||
private Map<String, List<String>> blacklists;
|
||||
private Map<String, List<String>> synonyms;
|
||||
|
||||
@JsonIgnore
|
||||
private Map<String, String> translationMap;
|
||||
|
||||
public Map<String, FieldDef> getModelMap() {
|
||||
return modelMap;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
private Map<String, FieldDef> modelMap;
|
||||
|
||||
@JsonIgnore
|
||||
public static PaceResolver resolver = new PaceResolver();
|
||||
|
||||
public PaceConfig() {}
|
||||
|
||||
public void initModel() {
|
||||
modelMap = Maps.newHashMap();
|
||||
for (FieldDef fd : getModel()) {
|
||||
modelMap.put(fd.getName(), fd);
|
||||
}
|
||||
}
|
||||
|
||||
public void initTranslationMap(){
|
||||
translationMap = Maps.newHashMap();
|
||||
|
||||
Transliterator transliterator = Transliterator.getInstance("Any-Eng");
|
||||
for (String key : synonyms.keySet()) {
|
||||
for (String term : synonyms.get(key)){
|
||||
translationMap.put(
|
||||
fixAliases(transliterator.transliterate(term.toLowerCase())),
|
||||
key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> translationMap(){
|
||||
return translationMap;
|
||||
}
|
||||
|
||||
public List<FieldDef> getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(final List<FieldDef> model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public List<ClusteringDef> getClustering() {
|
||||
return clustering;
|
||||
}
|
||||
|
||||
public void setClustering(final List<ClusteringDef> clustering) {
|
||||
this.clustering = clustering;
|
||||
}
|
||||
|
||||
public Map<String, TreeNodeDef> getDecisionTree() {
|
||||
return decisionTree;
|
||||
}
|
||||
|
||||
public void setDecisionTree(Map<String, TreeNodeDef> decisionTree) {
|
||||
this.decisionTree = decisionTree;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getBlacklists() {
|
||||
return blacklists;
|
||||
}
|
||||
|
||||
public void setBlacklists(final Map<String, List<String>> blacklists) {
|
||||
this.blacklists = blacklists;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getSynonyms() {
|
||||
return synonyms;
|
||||
}
|
||||
|
||||
public void setSynonyms(Map<String, List<String>> synonyms) {
|
||||
this.synonyms = synonyms;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package eu.dnetlib.pace.config;
|
||||
|
||||
public enum Type {
|
||||
String, Int, List, JSON, URL, StringConcat, DoubleArray
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package eu.dnetlib.pace.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class WfConfig implements Serializable {
|
||||
|
||||
/**
|
||||
* Entity type.
|
||||
*/
|
||||
private String entityType = "";
|
||||
|
||||
/**
|
||||
* Sub-Entity type refers to one of fields declared in the model. See eu.dnetlib.pace.config.PaceConfig.modelMap
|
||||
*/
|
||||
private String subEntityType = "";
|
||||
|
||||
/**
|
||||
* Sub-Entity value declares a value for subTypes to be considered.
|
||||
*/
|
||||
private String subEntityValue = "";
|
||||
|
||||
/**
|
||||
* Field name used to sort the values in the reducer phase.
|
||||
*/
|
||||
private String orderField = "";
|
||||
|
||||
/**
|
||||
* Column Families involved in the relations redirection.
|
||||
*/
|
||||
private List<String> rootBuilder = Lists.newArrayList();
|
||||
|
||||
/**
|
||||
* Set of datasource namespace prefixes that won't be deduplicated.
|
||||
*/
|
||||
private Set<String> skipList = Sets.newHashSet();
|
||||
|
||||
/**
|
||||
* Subprefix used to build the root id, allows multiple dedup runs.
|
||||
*/
|
||||
private String dedupRun = "";
|
||||
|
||||
/**
|
||||
* Similarity threshold.
|
||||
*/
|
||||
private double threshold = 0;
|
||||
|
||||
/** The queue max size. */
|
||||
private int queueMaxSize = 2000;
|
||||
|
||||
/** The group max size. */
|
||||
private int groupMaxSize;
|
||||
|
||||
/** The sliding window size. */
|
||||
private int slidingWindowSize;
|
||||
|
||||
/** The configuration id. */
|
||||
private String configurationId;
|
||||
|
||||
/** The include children. */
|
||||
private boolean includeChildren;
|
||||
|
||||
/** Default maximum number of allowed children. */
|
||||
private final static int MAX_CHILDREN = 10;
|
||||
|
||||
/** Maximum number of allowed children. */
|
||||
private int maxChildren = MAX_CHILDREN;
|
||||
|
||||
|
||||
/** Default maximum number of iterations. */
|
||||
private final static int MAX_ITERATIONS = 20;
|
||||
|
||||
/** Maximum number of iterations */
|
||||
private int maxIterations = MAX_ITERATIONS;
|
||||
|
||||
/** The Jquery path to retrieve the identifier */
|
||||
private String idPath = "$.id";
|
||||
|
||||
public WfConfig() {}
|
||||
|
||||
/**
|
||||
* Instantiates a new dedup config.
|
||||
*
|
||||
* @param entityType
|
||||
* the entity type
|
||||
* @param orderField
|
||||
* the order field
|
||||
* @param rootBuilder
|
||||
* the root builder families
|
||||
* @param dedupRun
|
||||
* the dedup run
|
||||
* @param skipList
|
||||
* the skip list
|
||||
* @param queueMaxSize
|
||||
* the queue max size
|
||||
* @param groupMaxSize
|
||||
* the group max size
|
||||
* @param slidingWindowSize
|
||||
* the sliding window size
|
||||
* @param includeChildren
|
||||
* allows the children to be included in the representative records or not.
|
||||
* @param maxIterations
|
||||
* the maximum number of iterations
|
||||
* @param idPath
|
||||
* the path for the id of the entity
|
||||
*/
|
||||
public WfConfig(final String entityType, final String orderField, final List<String> rootBuilder, final String dedupRun,
|
||||
final Set<String> skipList, final int queueMaxSize, final int groupMaxSize, final int slidingWindowSize, final boolean includeChildren, final int maxIterations, final String idPath) {
|
||||
super();
|
||||
this.entityType = entityType;
|
||||
this.orderField = orderField;
|
||||
this.rootBuilder = rootBuilder;
|
||||
this.dedupRun = cleanupStringNumber(dedupRun);
|
||||
this.skipList = skipList;
|
||||
this.queueMaxSize = queueMaxSize;
|
||||
this.groupMaxSize = groupMaxSize;
|
||||
this.slidingWindowSize = slidingWindowSize;
|
||||
this.includeChildren = includeChildren;
|
||||
this.maxIterations = maxIterations;
|
||||
this.idPath = idPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup string number.
|
||||
*
|
||||
* @param s
|
||||
* the s
|
||||
* @return the string
|
||||
*/
|
||||
private String cleanupStringNumber(final String s) {
|
||||
return s.contains("'") ? s.replaceAll("'", "") : s;
|
||||
}
|
||||
|
||||
public boolean hasSubType() {
|
||||
return StringUtils.isNotBlank(getSubEntityType()) && StringUtils.isNotBlank(getSubEntityValue());
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public void setEntityType(final String entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public String getSubEntityType() {
|
||||
return subEntityType;
|
||||
}
|
||||
|
||||
public void setSubEntityType(final String subEntityType) {
|
||||
this.subEntityType = subEntityType;
|
||||
}
|
||||
|
||||
public String getSubEntityValue() {
|
||||
return subEntityValue;
|
||||
}
|
||||
|
||||
public void setSubEntityValue(final String subEntityValue) {
|
||||
this.subEntityValue = subEntityValue;
|
||||
}
|
||||
|
||||
public String getOrderField() {
|
||||
return orderField;
|
||||
}
|
||||
|
||||
public void setOrderField(final String orderField) {
|
||||
this.orderField = orderField;
|
||||
}
|
||||
|
||||
public List<String> getRootBuilder() {
|
||||
return rootBuilder;
|
||||
}
|
||||
|
||||
public void setRootBuilder(final List<String> rootBuilder) {
|
||||
this.rootBuilder = rootBuilder;
|
||||
}
|
||||
|
||||
public Set<String> getSkipList() {
|
||||
return skipList != null ? skipList : new HashSet<String>();
|
||||
}
|
||||
|
||||
public void setSkipList(final Set<String> skipList) {
|
||||
this.skipList = skipList;
|
||||
}
|
||||
|
||||
public String getDedupRun() {
|
||||
return dedupRun;
|
||||
}
|
||||
|
||||
public void setDedupRun(final String dedupRun) {
|
||||
this.dedupRun = dedupRun;
|
||||
}
|
||||
|
||||
public double getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(final double threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public int getQueueMaxSize() {
|
||||
return queueMaxSize;
|
||||
}
|
||||
|
||||
public void setQueueMaxSize(final int queueMaxSize) {
|
||||
this.queueMaxSize = queueMaxSize;
|
||||
}
|
||||
|
||||
public int getGroupMaxSize() {
|
||||
return groupMaxSize;
|
||||
}
|
||||
|
||||
public void setGroupMaxSize(final int groupMaxSize) {
|
||||
this.groupMaxSize = groupMaxSize;
|
||||
}
|
||||
|
||||
public int getSlidingWindowSize() {
|
||||
return slidingWindowSize;
|
||||
}
|
||||
|
||||
public void setSlidingWindowSize(final int slidingWindowSize) {
|
||||
this.slidingWindowSize = slidingWindowSize;
|
||||
}
|
||||
|
||||
public String getConfigurationId() {
|
||||
return configurationId;
|
||||
}
|
||||
|
||||
public void setConfigurationId(final String configurationId) {
|
||||
this.configurationId = configurationId;
|
||||
}
|
||||
|
||||
public boolean isIncludeChildren() {
|
||||
return includeChildren;
|
||||
}
|
||||
|
||||
public void setIncludeChildren(final boolean includeChildren) {
|
||||
this.includeChildren = includeChildren;
|
||||
}
|
||||
|
||||
public int getMaxChildren() {
|
||||
return maxChildren;
|
||||
}
|
||||
|
||||
public void setMaxChildren(final int maxChildren) {
|
||||
this.maxChildren = maxChildren;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxIterations() {
|
||||
return maxIterations;
|
||||
}
|
||||
|
||||
public void setMaxIterations(int maxIterations) {
|
||||
this.maxIterations = maxIterations;
|
||||
}
|
||||
|
||||
public String getIdPath() {
|
||||
return idPath;
|
||||
}
|
||||
|
||||
public void setIdPath(String idPath) {
|
||||
this.idPath = idPath;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("unable to serialise " + this.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.pace.model;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.dnetlib.pace.clustering.ClusteringFunction;
|
||||
import eu.dnetlib.pace.config.PaceConfig;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class ClusteringDef implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
private List<String> fields;
|
||||
|
||||
private Map<String, Integer> params;
|
||||
|
||||
public ClusteringDef() {}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ClusteringFunction clusteringFunction() {
|
||||
return PaceConfig.resolver.getClusteringFunction(getName(), params);
|
||||
}
|
||||
|
||||
public List<String> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(final List<String> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(final Map<String, Integer> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("unable to serialise " + this.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package eu.dnetlib.pace.model;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Type;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The schema is composed by field definitions (FieldDef). Each field has a type, a name, and an associated compare algorithm.
|
||||
*/
|
||||
public class FieldDef implements Serializable {
|
||||
|
||||
public final static String PATH_SEPARATOR = "/";
|
||||
|
||||
private String name;
|
||||
|
||||
private String path;
|
||||
|
||||
private Type type;
|
||||
|
||||
private boolean overrideMatch;
|
||||
|
||||
/**
|
||||
* Sets maximum size for the repeatable fields in the model. -1 for unbounded size.
|
||||
*/
|
||||
private int size = -1;
|
||||
|
||||
/**
|
||||
* Sets maximum length for field values in the model. -1 for unbounded length.
|
||||
*/
|
||||
private int length = -1;
|
||||
|
||||
public FieldDef() {}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public List<String> getPathList() {
|
||||
return Lists.newArrayList(Splitter.on(PATH_SEPARATOR).split(getPath()));
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isOverrideMatch() {
|
||||
return overrideMatch;
|
||||
}
|
||||
|
||||
public void setOverrideMatch(final boolean overrideMatch) {
|
||||
this.overrideMatch = overrideMatch;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package eu.dnetlib.pace.model;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.Normalizer;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.hash.Hashing;
|
||||
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.util.Capitalise;
|
||||
import eu.dnetlib.pace.util.DotAbbreviations;
|
||||
|
||||
public class Person {
|
||||
|
||||
private static final String UTF8 = "UTF-8";
|
||||
private List<String> name = Lists.newArrayList();
|
||||
private List<String> surname = Lists.newArrayList();
|
||||
private List<String> fullname = Lists.newArrayList();
|
||||
private final String original;
|
||||
|
||||
private static Set<String> particles = null;
|
||||
|
||||
public Person(String s, final boolean aggressive) {
|
||||
original = s;
|
||||
s = Normalizer.normalize(s, Normalizer.Form.NFD);
|
||||
s = s.replaceAll("\\(.+\\)", "");
|
||||
s = s.replaceAll("\\[.+\\]", "");
|
||||
s = s.replaceAll("\\{.+\\}", "");
|
||||
s = s.replaceAll("\\s+-\\s+", "-");
|
||||
s = s.replaceAll("[\\p{Punct}&&[^,-]]", " ");
|
||||
s = s.replaceAll("\\d", " ");
|
||||
s = s.replaceAll("\\n", " ");
|
||||
s = s.replaceAll("\\.", " ");
|
||||
s = s.replaceAll("\\s+", " ");
|
||||
|
||||
if (aggressive) {
|
||||
s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}&&[^,-]]", "");
|
||||
// s = s.replaceAll("[\\W&&[^,-]]", "");
|
||||
}
|
||||
|
||||
if (s.contains(",")) { //if the name contains a comma it is easy derivable the name and the surname
|
||||
final String[] arr = s.split(",");
|
||||
if (arr.length == 1) {
|
||||
fullname = splitTerms(arr[0]);
|
||||
} else if (arr.length > 1) {
|
||||
surname = splitTerms(arr[0]);
|
||||
name = splitTerms(arr[1]);
|
||||
fullname.addAll(surname);
|
||||
fullname.addAll(name);
|
||||
}
|
||||
} else {
|
||||
fullname = splitTerms(s);
|
||||
|
||||
int lastInitialPosition = fullname.size();
|
||||
boolean hasSurnameInUpperCase = false;
|
||||
|
||||
for (int i = 0; i < fullname.size(); i++) {
|
||||
final String term = fullname.get(i);
|
||||
if (term.length() == 1) {
|
||||
lastInitialPosition = i;
|
||||
} else if (term.equals(term.toUpperCase())) {
|
||||
hasSurnameInUpperCase = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastInitialPosition < (fullname.size() - 1)) { // Case: Michele G. Artini
|
||||
name = fullname.subList(0, lastInitialPosition + 1);
|
||||
surname = fullname.subList(lastInitialPosition + 1, fullname.size());
|
||||
} else if (hasSurnameInUpperCase) { // Case: Michele ARTINI
|
||||
for (final String term : fullname) {
|
||||
if ((term.length() > 1) && term.equals(term.toUpperCase())) {
|
||||
surname.add(term);
|
||||
} else {
|
||||
name.add(term);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitTerms(final String s) {
|
||||
if (particles == null) {
|
||||
particles = AbstractPaceFunctions.loadFromClasspath("/eu/dnetlib/pace/config/name_particles.txt");
|
||||
}
|
||||
|
||||
final List<String> list = Lists.newArrayList();
|
||||
for (final String part : Splitter.on(" ").omitEmptyStrings().split(s)) {
|
||||
if (!particles.contains(part.toLowerCase())) {
|
||||
list.add(part);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<String> getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getNameString() {
|
||||
return Joiner.on(" ").join(getName());
|
||||
}
|
||||
|
||||
public List<String> getSurname() {
|
||||
return surname;
|
||||
}
|
||||
|
||||
public List<String> getFullname() {
|
||||
return fullname;
|
||||
}
|
||||
|
||||
public String getOriginal() {
|
||||
return original;
|
||||
}
|
||||
|
||||
public String hash() {
|
||||
return Hashing.murmur3_128().hashString(getNormalisedFullname(), Charset.forName(UTF8)).toString();
|
||||
}
|
||||
|
||||
public String getNormalisedFirstName() {
|
||||
return Joiner.on(" ").join(getCapitalFirstnames());
|
||||
}
|
||||
|
||||
public String getNormalisedSurname() {
|
||||
return Joiner.on(" ").join(getCapitalSurname());
|
||||
}
|
||||
|
||||
public String getSurnameString() {
|
||||
return Joiner.on(" ").join(getSurname());
|
||||
}
|
||||
|
||||
public String getNormalisedFullname() {
|
||||
return isAccurate() ? getNormalisedSurname() + ", " + getNormalisedFirstName() : Joiner.on(" ").join(fullname);
|
||||
}
|
||||
|
||||
public List<String> getCapitalFirstnames() {
|
||||
return Lists.newArrayList(Iterables.transform(getNameWithAbbreviations(), new Capitalise()));
|
||||
}
|
||||
|
||||
public List<String> getCapitalSurname() {
|
||||
return Lists.newArrayList(Iterables.transform(surname, new Capitalise()));
|
||||
}
|
||||
|
||||
public List<String> getNameWithAbbreviations() {
|
||||
return Lists.newArrayList(Iterables.transform(name, new DotAbbreviations()));
|
||||
}
|
||||
|
||||
public boolean isAccurate() {
|
||||
return ((name != null) && (surname != null) && !name.isEmpty() && !surname.isEmpty());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package eu.dnetlib.pace.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
public class PersonComparatorUtils {
|
||||
|
||||
private static final int MAX_FULLNAME_LENGTH = 50;
|
||||
|
||||
public static Set<String> getNgramsForPerson(String fullname) {
|
||||
|
||||
Set<String> set = Sets.newHashSet();
|
||||
|
||||
if (fullname.length() > MAX_FULLNAME_LENGTH) {
|
||||
return set;
|
||||
}
|
||||
|
||||
Person p = new Person(fullname, true);
|
||||
|
||||
if (p.isAccurate()) {
|
||||
for (String name : p.getName()) {
|
||||
for (String surname : p.getSurname()) {
|
||||
set.add((name.charAt(0) + "_" + surname).toLowerCase());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
List<String> list = p.getFullname();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (list.get(i).length() > 1) {
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
if (i != j) {
|
||||
set.add((list.get(j).charAt(0) + "_" + list.get(i)).toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
public static boolean areSimilar(String s1, String s2) {
|
||||
Person p1 = new Person(s1, true);
|
||||
Person p2 = new Person(s2, true);
|
||||
|
||||
if (p1.isAccurate() && p2.isAccurate()) {
|
||||
return verifyNames(p1.getName(), p2.getName()) && verifySurnames(p1.getSurname(), p2.getSurname());
|
||||
} else {
|
||||
return verifyFullnames(p1.getFullname(), p2.getFullname());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean verifyNames(List<String> list1, List<String> list2) {
|
||||
return verifySimilarity(extractExtendedNames(list1), extractExtendedNames(list2))
|
||||
&& verifySimilarity(extractInitials(list1), extractInitials(list2));
|
||||
}
|
||||
|
||||
private static boolean verifySurnames(List<String> list1, List<String> list2) {
|
||||
if (list1.size() != list2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
if (!list1.get(i).equalsIgnoreCase(list2.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean verifyFullnames(List<String> list1, List<String> list2) {
|
||||
Collections.sort(list1);
|
||||
Collections.sort(list2);
|
||||
return verifySimilarity(extractExtendedNames(list1), extractExtendedNames(list2))
|
||||
&& verifySimilarity(extractInitials(list1), extractInitials(list2));
|
||||
}
|
||||
|
||||
private static List<String> extractExtendedNames(List<String> list) {
|
||||
ArrayList<String> res = Lists.newArrayList();
|
||||
for (String s : list) {
|
||||
if (s.length() > 1) {
|
||||
res.add(s.toLowerCase());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static List<String> extractInitials(List<String> list) {
|
||||
ArrayList<String> res = Lists.newArrayList();
|
||||
for (String s : list) {
|
||||
res.add(s.substring(0, 1).toLowerCase());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static boolean verifySimilarity(List<String> list1, List<String> list2) {
|
||||
if (list1.size() > list2.size()) {
|
||||
return verifySimilarity(list2, list1);
|
||||
}
|
||||
|
||||
// NB: List2 is greater than list1 (or equal)
|
||||
int pos = -1;
|
||||
for (String s : list1) {
|
||||
int curr = list2.indexOf(s);
|
||||
if (curr > pos) {
|
||||
list2.set(curr, "*"); // I invalidate the found element, example: "amm - amm"
|
||||
pos = curr;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package eu.dnetlib.pace.model;
|
||||
|
||||
import eu.dnetlib.pace.clustering.NGramUtils;
|
||||
import org.apache.spark.sql.Row;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* The Class MapDocumentComparator.
|
||||
*/
|
||||
public class RowDataOrderingComparator implements Comparator<Row> {
|
||||
|
||||
/** The comparator field. */
|
||||
private int comparatorField;
|
||||
|
||||
/**
|
||||
* Instantiates a new map document comparator.
|
||||
*
|
||||
* @param comparatorField
|
||||
* the comparator field
|
||||
*/
|
||||
public RowDataOrderingComparator(final int comparatorField) {
|
||||
this.comparatorField = comparatorField;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compare(final Row d1, final Row d2) {
|
||||
if (d1 == null)
|
||||
return d2==null ? 0: -1;
|
||||
else if (d2 == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
final String o1 = d1.getString(comparatorField);
|
||||
final String o2 = d2.getString(comparatorField);
|
||||
|
||||
if (o1 == null)
|
||||
return o2==null ? 0: -1;
|
||||
else if (o2 == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
final String to1 = NGramUtils.cleanupForOrdering(o1);
|
||||
final String to2 = NGramUtils.cleanupForOrdering(o2);
|
||||
|
||||
return to1.compareTo(to2);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("alwaysMatch")
|
||||
public class AlwaysMatch<T> extends AbstractComparator<T> {
|
||||
|
||||
public AlwaysMatch(final Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
public AlwaysMatch(final double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected AlwaysMatch(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final Object a, final Object b, final Config conf) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.model.Person;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ComparatorClass("authorsMatch")
|
||||
public class AuthorsMatch extends AbstractListComparator {
|
||||
|
||||
Map<String, String> params;
|
||||
|
||||
private double SURNAME_THRESHOLD;
|
||||
private double NAME_THRESHOLD;
|
||||
private double FULLNAME_THRESHOLD;
|
||||
private String MODE; //full or surname
|
||||
private int SIZE_THRESHOLD;
|
||||
private String TYPE; //count or percentage
|
||||
private int common;
|
||||
|
||||
public AuthorsMatch(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
this.params = params;
|
||||
|
||||
MODE = params.getOrDefault("mode", "full");
|
||||
SURNAME_THRESHOLD = Double.parseDouble(params.getOrDefault("surname_th", "0.95"));
|
||||
NAME_THRESHOLD = Double.parseDouble(params.getOrDefault("name_th", "0.95"));
|
||||
FULLNAME_THRESHOLD = Double.parseDouble(params.getOrDefault("fullname_th", "0.9"));
|
||||
SIZE_THRESHOLD = Integer.parseInt(params.getOrDefault("size_th", "20"));
|
||||
TYPE = params.getOrDefault("type", "percentage");
|
||||
common = 0;
|
||||
}
|
||||
|
||||
protected AuthorsMatch(double w, AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final List<String> a, final List<String> b, final Config conf) {
|
||||
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1;
|
||||
|
||||
if (a.size() > SIZE_THRESHOLD || b.size() > SIZE_THRESHOLD)
|
||||
return 1.0;
|
||||
|
||||
List<Person> aList = a.stream().map(author -> new Person(author, false)).collect(Collectors.toList());
|
||||
List<Person> bList = b.stream().map(author -> new Person(author, false)).collect(Collectors.toList());
|
||||
|
||||
common = 0;
|
||||
//compare each element of List1 with each element of List2
|
||||
for (Person p1 : aList)
|
||||
|
||||
for (Person p2 : bList) {
|
||||
|
||||
//both persons are inaccurate
|
||||
if (!p1.isAccurate() && !p2.isAccurate()) {
|
||||
//compare just normalized fullnames
|
||||
String fullname1 = normalization(p1.getNormalisedFullname().isEmpty()? p1.getOriginal() : p1.getNormalisedFullname());
|
||||
String fullname2 = normalization(p2.getNormalisedFullname().isEmpty()? p2.getOriginal() : p2.getNormalisedFullname());
|
||||
|
||||
if (ssalgo.score(fullname1, fullname2) > FULLNAME_THRESHOLD) {
|
||||
common += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//one person is inaccurate
|
||||
if (p1.isAccurate() ^ p2.isAccurate()) {
|
||||
//prepare data
|
||||
//data for the accurate person
|
||||
String name = normalization(p1.isAccurate()? p1.getNormalisedFirstName() : p2.getNormalisedFirstName());
|
||||
String surname = normalization(p1.isAccurate()? p1.getNormalisedSurname() : p2.getNormalisedSurname());
|
||||
|
||||
//data for the inaccurate person
|
||||
String fullname = normalization(
|
||||
p1.isAccurate() ? ((p2.getNormalisedFullname().isEmpty()) ? p2.getOriginal() : p2.getNormalisedFullname()) : (p1.getNormalisedFullname().isEmpty() ? p1.getOriginal() : p1.getNormalisedFullname())
|
||||
);
|
||||
|
||||
if (fullname.contains(surname)) {
|
||||
if (MODE.equals("full")) {
|
||||
if (fullname.contains(name)) {
|
||||
common += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { //MODE equals "surname"
|
||||
common += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//both persons are accurate
|
||||
if (p1.isAccurate() && p2.isAccurate()) {
|
||||
|
||||
if (compareSurname(p1, p2)) {
|
||||
if (MODE.equals("full")) {
|
||||
if(compareFirstname(p1, p2)) {
|
||||
common += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { //MODE equals "surname"
|
||||
common += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//normalization factor to compute the score
|
||||
int normFactor = aList.size() == bList.size() ? aList.size() : (aList.size() + bList.size() - common);
|
||||
|
||||
if(TYPE.equals("percentage")) {
|
||||
return (double) common / normFactor;
|
||||
}
|
||||
else {
|
||||
return (double) common;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean compareSurname(Person p1, Person p2) {
|
||||
return ssalgo.score(normalization(p1.getNormalisedSurname()), normalization(p2.getNormalisedSurname())) > SURNAME_THRESHOLD;
|
||||
}
|
||||
|
||||
public boolean compareFirstname(Person p1, Person p2) {
|
||||
|
||||
if(p1.getNormalisedFirstName().length()<=2 || p2.getNormalisedFirstName().length()<=2) {
|
||||
if (firstLC(p1.getNormalisedFirstName()).equals(firstLC(p2.getNormalisedFirstName())))
|
||||
return true;
|
||||
}
|
||||
|
||||
return ssalgo.score(normalization(p1.getNormalisedFirstName()), normalization(p2.getNormalisedFirstName())) > NAME_THRESHOLD;
|
||||
}
|
||||
|
||||
public String normalization(String s) {
|
||||
return normalize(utf8(cleanup(s)));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ComparatorClass("cityMatch")
|
||||
public class CityMatch extends AbstractStringComparator {
|
||||
|
||||
private Map<String, String> params;
|
||||
|
||||
public CityMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
ca = normalize(ca);
|
||||
cb = normalize(cb);
|
||||
|
||||
ca = filterAllStopWords(ca);
|
||||
cb = filterAllStopWords(cb);
|
||||
|
||||
Set<String> cities1 = getCities(ca, Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
Set<String> cities2 = getCities(cb, Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
|
||||
Set<String> codes1 = citiesToCodes(cities1);
|
||||
Set<String> codes2 = citiesToCodes(cities2);
|
||||
|
||||
//if no cities are detected, the comparator gives 1.0
|
||||
if (codes1.isEmpty() && codes2.isEmpty())
|
||||
return 1.0;
|
||||
else {
|
||||
if (codes1.isEmpty() ^ codes2.isEmpty())
|
||||
return -1; //undefined if one of the two has no cities
|
||||
return commonElementsPercentage(codes1, codes2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("cosineSimilarity")
|
||||
public class CosineSimilarity extends AbstractComparator<double[]> {
|
||||
|
||||
Map<String, String> params;
|
||||
|
||||
public CosineSimilarity(Map<String,String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(Object a, Object b, Config config) {
|
||||
return compare((double[])a, (double[])b, config);
|
||||
}
|
||||
|
||||
public double compare(final double[] a, final double[] b, final Config conf) {
|
||||
|
||||
if (a.length == 0 || b.length == 0)
|
||||
return -1;
|
||||
|
||||
return cosineSimilarity(a, b);
|
||||
}
|
||||
|
||||
double cosineSimilarity(double[] a, double[] b) {
|
||||
double dotProduct = 0;
|
||||
double normASum = 0;
|
||||
double normBSum = 0;
|
||||
|
||||
for(int i = 0; i < a.length; i ++) {
|
||||
dotProduct += a[i] * b[i];
|
||||
normASum += a[i] * a[i];
|
||||
normBSum += b[i] * b[i];
|
||||
}
|
||||
|
||||
double eucledianDist = Math.sqrt(normASum) * Math.sqrt(normBSum);
|
||||
return dotProduct / eucledianDist;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class ExactMatch.
|
||||
*
|
||||
* @author claudio
|
||||
*/
|
||||
@ComparatorClass("doiExactMatch")
|
||||
public class DoiExactMatch extends ExactMatchIgnoreCase {
|
||||
|
||||
public final String PREFIX = "(http:\\/\\/dx\\.doi\\.org\\/)|(doi:)";
|
||||
|
||||
public DoiExactMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toString(final Object f) {
|
||||
return super.toString(f).replaceAll(PREFIX, "");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("domainExactMatch")
|
||||
public class DomainExactMatch extends ExactMatchIgnoreCase {
|
||||
|
||||
public DomainExactMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toString(final Object f) {
|
||||
|
||||
try {
|
||||
return asUrl(super.toString(f)).getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private URL asUrl(final String value) throws MalformedURLException {
|
||||
return new URL(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("exactMatch")
|
||||
public class ExactMatch extends AbstractStringComparator {
|
||||
|
||||
public ExactMatch(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
public ExactMatch(final double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected ExactMatch(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty()) {
|
||||
return -1.0; //return -1 if a field is missing
|
||||
}
|
||||
return a.equals(b) ? 1.0 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("exactMatchIgnoreCase")
|
||||
public class ExactMatchIgnoreCase extends AbstractStringComparator {
|
||||
|
||||
public ExactMatchIgnoreCase(Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(String a, String b, final Config conf) {
|
||||
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1;
|
||||
|
||||
return a.equalsIgnoreCase(b) ? 1 : 0;
|
||||
}
|
||||
|
||||
protected String toString(final Object object) {
|
||||
return toFirstString(object);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ComparatorClass("instanceTypeMatch")
|
||||
public class InstanceTypeMatch extends AbstractListComparator {
|
||||
|
||||
final Map<String, String> translationMap = new HashMap<>();
|
||||
|
||||
public InstanceTypeMatch(Map<String, String> params){
|
||||
super(params);
|
||||
|
||||
//jolly types
|
||||
translationMap.put("Conference object", "*");
|
||||
translationMap.put("Other literature type", "*");
|
||||
translationMap.put("Unknown", "*");
|
||||
|
||||
//article types
|
||||
translationMap.put("Article", "Article");
|
||||
translationMap.put("Data Paper", "Article");
|
||||
translationMap.put("Software Paper", "Article");
|
||||
translationMap.put("Preprint", "Article");
|
||||
|
||||
//thesis types
|
||||
translationMap.put("Thesis", "Thesis");
|
||||
translationMap.put("Master thesis", "Thesis");
|
||||
translationMap.put("Bachelor thesis", "Thesis");
|
||||
translationMap.put("Doctoral thesis", "Thesis");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double compare(final List<String> a, final List<String> b, final Config conf) {
|
||||
|
||||
if (a == null || b == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (a.isEmpty() || b.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final Set<String> ca = a.stream().map(this::translate).collect(Collectors.toSet());
|
||||
final Set<String> cb = b.stream().map(this::translate).collect(Collectors.toSet());
|
||||
|
||||
//if at least one is a jolly type, it must produce a match
|
||||
if (ca.contains("*") || cb.contains("*"))
|
||||
return 1.0;
|
||||
|
||||
int incommon = Sets.intersection(ca, cb).size();
|
||||
|
||||
//if at least one is in common, it must produce a match
|
||||
return incommon >= 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
public String translate(String term){
|
||||
return translationMap.getOrDefault(term, term);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
//case class JaroWinkler(w: Double) extends SecondStringDistanceAlgo(w, new com.wcohen.ss.JaroWinkler())
|
||||
@ComparatorClass("jaroWinkler")
|
||||
public class JaroWinkler extends AbstractStringComparator {
|
||||
|
||||
public JaroWinkler(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
public JaroWinkler(double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected JaroWinkler(double weight, AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, final Config conf) {
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
return normalize(ssalgo.score(ca, cb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ComparatorClass("jaroWinklerNormalizedName")
|
||||
public class JaroWinklerNormalizedName extends AbstractStringComparator {
|
||||
|
||||
private Map<String, String> params;
|
||||
|
||||
public JaroWinklerNormalizedName(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public JaroWinklerNormalizedName(double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected JaroWinklerNormalizedName(double weight, AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, final Config conf) {
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
ca = normalize(ca);
|
||||
cb = normalize(cb);
|
||||
|
||||
ca = filterAllStopWords(ca);
|
||||
cb = filterAllStopWords(cb);
|
||||
|
||||
Set<String> keywords1 = getKeywords(ca, conf.translationMap(), Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
Set<String> keywords2 = getKeywords(cb, conf.translationMap(), Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
|
||||
Set<String> cities1 = getCities(ca, Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
Set<String> cities2 = getCities(cb, Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
|
||||
ca = removeKeywords(ca, keywords1);
|
||||
ca = removeKeywords(ca, cities1);
|
||||
cb = removeKeywords(cb, keywords2);
|
||||
cb = removeKeywords(cb, cities2);
|
||||
|
||||
ca = ca.replaceAll("[ ]{2,}", " ");
|
||||
cb = cb.replaceAll("[ ]{2,}", " ");
|
||||
|
||||
if (ca.isEmpty() && cb.isEmpty())
|
||||
return 1.0;
|
||||
else
|
||||
return normalize(ssalgo.score(ca,cb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
//case class JaroWinkler(w: Double) extends SecondStringDistanceAlgo(w, new com.wcohen.ss.JaroWinkler())
|
||||
@ComparatorClass("jaroWinklerTitle")
|
||||
public class JaroWinklerTitle extends AbstractStringComparator {
|
||||
|
||||
public JaroWinklerTitle(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
public JaroWinklerTitle(double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected JaroWinklerTitle(double weight, AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, final Config conf) {
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
boolean check = checkNumbers(ca, cb);
|
||||
return check ? 0.5 : normalize(ssalgo.score(ca, cb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import eu.dnetlib.pace.util.MapDocumentUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ComparatorClass("jsonListMatch")
|
||||
public class JsonListMatch extends AbstractListComparator {
|
||||
|
||||
private static final Log log = LogFactory.getLog(JsonListMatch.class);
|
||||
private Map<String, String> params;
|
||||
|
||||
private String MODE; //"percentage" or "count"
|
||||
|
||||
public JsonListMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
|
||||
MODE = params.getOrDefault("mode", "percentage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final List<String> sa, final List<String> sb, final Config conf) {
|
||||
if (sa.isEmpty() || sb.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final Set<String> ca = sa.stream().map(this::toComparableString).collect(Collectors.toSet());
|
||||
final Set<String> cb = sb.stream().map(this::toComparableString).collect(Collectors.toSet());
|
||||
|
||||
int incommon = Sets.intersection(ca, cb).size();
|
||||
int simDiff = Sets.symmetricDifference(ca, cb).size();
|
||||
|
||||
if (incommon + simDiff == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (MODE.equals("percentage"))
|
||||
return (double)incommon / (incommon + simDiff);
|
||||
else
|
||||
return incommon;
|
||||
|
||||
}
|
||||
|
||||
//converts every json into a comparable string basing on parameters
|
||||
private String toComparableString(String json){
|
||||
|
||||
StringBuilder st = new StringBuilder(); //to build the string used for comparisons basing on the jpath into parameters
|
||||
|
||||
//for each path in the param list
|
||||
for (String key: params.keySet().stream().filter(k -> k.contains("jpath")).collect(Collectors.toList())) {
|
||||
String path = params.get(key);
|
||||
String value = MapDocumentUtil.getJPathString(path, json);
|
||||
if (value == null || value.isEmpty())
|
||||
value = "";
|
||||
st.append(value);
|
||||
st.append("::");
|
||||
}
|
||||
|
||||
st.setLength(st.length()-2);
|
||||
return st.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ComparatorClass("keywordMatch")
|
||||
public class KeywordMatch extends AbstractStringComparator {
|
||||
|
||||
Map<String, String> params;
|
||||
|
||||
public KeywordMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
ca = normalize(ca);
|
||||
cb = normalize(cb);
|
||||
|
||||
ca = filterAllStopWords(ca);
|
||||
cb = filterAllStopWords(cb);
|
||||
|
||||
Set<String> keywords1 = getKeywords(ca, conf.translationMap(), Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
Set<String> keywords2 = getKeywords(cb, conf.translationMap(), Integer.parseInt(params.getOrDefault("windowSize", "4")));
|
||||
|
||||
Set<String> codes1 = toCodes(keywords1, conf.translationMap());
|
||||
Set<String> codes2 = toCodes(keywords2, conf.translationMap());
|
||||
|
||||
//if no cities are detected, the comparator gives 1.0
|
||||
if (codes1.isEmpty() && codes2.isEmpty())
|
||||
return 1.0;
|
||||
else {
|
||||
if (codes1.isEmpty() ^ codes2.isEmpty())
|
||||
return -1.0; //undefined if one of the two has no keywords
|
||||
return commonElementsPercentage(codes1, codes2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("level2JaroWinkler")
|
||||
public class Level2JaroWinkler extends AbstractStringComparator {
|
||||
|
||||
public Level2JaroWinkler(Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
public Level2JaroWinkler(double w) {
|
||||
super(w, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
protected Level2JaroWinkler(double w, AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("level2JaroWinklerTitle")
|
||||
public class Level2JaroWinklerTitle extends AbstractStringComparator {
|
||||
|
||||
public Level2JaroWinklerTitle(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
public Level2JaroWinklerTitle(final double w) {
|
||||
super(w, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
protected Level2JaroWinklerTitle(final double w, final AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
final String ca = cleanup(a);
|
||||
final String cb = cleanup(b);
|
||||
|
||||
final boolean check = checkNumbers(ca, cb);
|
||||
|
||||
if (check) return 0.5;
|
||||
|
||||
return ssalgo.score(ca, cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("level2Levenstein")
|
||||
public class Level2Levenstein extends AbstractStringComparator {
|
||||
|
||||
public Level2Levenstein(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Level2Levenstein());
|
||||
}
|
||||
|
||||
public Level2Levenstein(double w) {
|
||||
super(w, new com.wcohen.ss.Level2Levenstein());
|
||||
}
|
||||
|
||||
protected Level2Levenstein(double w, AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return 1 / Math.pow(Math.abs(d) + 1, 0.1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("levenstein")
|
||||
public class Levenstein extends AbstractStringComparator {
|
||||
|
||||
public Levenstein(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
public Levenstein(double w) {
|
||||
super(w, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
protected Levenstein(double w, AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(double d) {
|
||||
return 1 / Math.pow(Math.abs(d) + 1, 0.1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("levensteinTitle")
|
||||
public class LevensteinTitle extends AbstractStringComparator {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LevensteinTitle.class);
|
||||
|
||||
public LevensteinTitle(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
public LevensteinTitle(final double w) {
|
||||
super(w, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
protected LevensteinTitle(final double w, final AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
final String ca = cleanup(a);
|
||||
final String cb = cleanup(b);
|
||||
|
||||
final boolean check = checkNumbers(ca, cb);
|
||||
|
||||
if (check) return 0.5;
|
||||
|
||||
return normalize(ssalgo.score(ca, cb), ca.length(), cb.length());
|
||||
}
|
||||
|
||||
private double normalize(final double score, final int la, final int lb) {
|
||||
return 1 - (Math.abs(score) / Math.max(la, lb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return 1 / Math.pow(Math.abs(d) + 1, 0.1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Compared compare between two titles, ignoring version numbers. Suitable for Software entities.
|
||||
*/
|
||||
@ComparatorClass("levensteinTitleIgnoreVersion")
|
||||
public class LevensteinTitleIgnoreVersion extends AbstractStringComparator {
|
||||
|
||||
public LevensteinTitleIgnoreVersion(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
public LevensteinTitleIgnoreVersion(final double w) {
|
||||
super(w, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
protected LevensteinTitleIgnoreVersion(final double w, final AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
String ca = cleanup(a);
|
||||
String cb = cleanup(b);
|
||||
|
||||
ca = ca.replaceAll("\\d", "").replaceAll(getRomans(ca), "").trim();
|
||||
cb = cb.replaceAll("\\d", "").replaceAll(getRomans(cb), "").trim();
|
||||
|
||||
ca = filterAllStopWords(ca);
|
||||
cb = filterAllStopWords(cb);
|
||||
|
||||
return normalize(ssalgo.score(ca, cb), ca.length(), cb.length());
|
||||
}
|
||||
|
||||
private double normalize(final double score, final int la, final int lb) {
|
||||
return 1 - (Math.abs(score) / Math.max(la, lb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return 1 / Math.pow(Math.abs(d) + 1, 0.1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The Class Contains match
|
||||
*
|
||||
* @author miconis
|
||||
* */
|
||||
@ComparatorClass("listContainsMatch")
|
||||
public class ListContainsMatch extends AbstractListComparator {
|
||||
|
||||
private Map<String, String> params;
|
||||
private boolean CASE_SENSITIVE;
|
||||
private String STRING;
|
||||
private String AGGREGATOR;
|
||||
|
||||
public ListContainsMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
|
||||
//read parameters
|
||||
CASE_SENSITIVE = Boolean.parseBoolean(params.getOrDefault("caseSensitive", "false"));
|
||||
STRING = params.get("string");
|
||||
AGGREGATOR = params.get("bool");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(List<String> sa, List<String> sb, Config conf) {
|
||||
if (sa.isEmpty() || sb.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CASE_SENSITIVE) {
|
||||
sa = sa.stream().map(String::toLowerCase).collect(Collectors.toList());
|
||||
sb = sb.stream().map(String::toLowerCase).collect(Collectors.toList());
|
||||
STRING = STRING.toLowerCase();
|
||||
}
|
||||
|
||||
switch(AGGREGATOR) {
|
||||
case "AND":
|
||||
if(sa.contains(STRING) && sb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
case "OR":
|
||||
if(sa.contains(STRING) || sb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
case "XOR":
|
||||
if(sa.contains(STRING) ^ sb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
return 0.0;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("mustBeDifferent")
|
||||
public class MustBeDifferent extends AbstractStringComparator {
|
||||
|
||||
public MustBeDifferent(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
public MustBeDifferent(final double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
protected MustBeDifferent(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
return !a.equals(b) ? 1.0 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.Comparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Not all fields of a document need to partecipate in the compare measure. We model those fields as having a
|
||||
* NullDistanceAlgo.
|
||||
*/
|
||||
@ComparatorClass("null")
|
||||
public class NullDistanceAlgo<T> implements Comparator<T> {
|
||||
|
||||
public NullDistanceAlgo(Map<String, String> params){
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(Object a, Object b, Config config) {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("numbersComparator")
|
||||
public class NumbersComparator extends AbstractStringComparator {
|
||||
|
||||
Map<String, String> params;
|
||||
|
||||
public NumbersComparator(Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, Config conf) {
|
||||
|
||||
//extracts numbers from the field
|
||||
String numbers1 = getNumbers(nfd(a));
|
||||
String numbers2 = getNumbers(nfd(b));
|
||||
|
||||
if (numbers1.isEmpty() || numbers2.isEmpty())
|
||||
return -1.0;
|
||||
|
||||
int n1 = Integer.parseInt(numbers1);
|
||||
int n2 = Integer.parseInt(numbers2);
|
||||
|
||||
return Math.abs(n1 - n2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("numbersMatch")
|
||||
public class NumbersMatch extends AbstractStringComparator {
|
||||
|
||||
|
||||
public NumbersMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, Config conf) {
|
||||
|
||||
//extracts numbers from the field
|
||||
String numbers1 = getNumbers(nfd(a));
|
||||
String numbers2 = getNumbers(nfd(b));
|
||||
|
||||
if (numbers1.isEmpty() && numbers2.isEmpty())
|
||||
return 1.0;
|
||||
|
||||
if (numbers1.isEmpty() || numbers2.isEmpty())
|
||||
return -1.0;
|
||||
|
||||
if (numbers1.equals(numbers2))
|
||||
return 1.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("romansMatch")
|
||||
public class RomansMatch extends AbstractStringComparator {
|
||||
|
||||
|
||||
public RomansMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, Config conf) {
|
||||
|
||||
//extracts romans from the field
|
||||
String romans1 = getRomans(nfd(a));
|
||||
String romans2 = getRomans(nfd(b));
|
||||
|
||||
if (romans1.isEmpty() && romans2.isEmpty())
|
||||
return 1.0;
|
||||
|
||||
if (romans1.isEmpty() || romans2.isEmpty())
|
||||
return -1.0;
|
||||
|
||||
if (romans1.equals(romans2))
|
||||
return 1.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Returns true if the number of values in the fields is the same.
|
||||
*
|
||||
* @author claudio
|
||||
*/
|
||||
@ComparatorClass("sizeMatch")
|
||||
public class SizeMatch extends AbstractListComparator {
|
||||
|
||||
/**
|
||||
* Instantiates a new size match.
|
||||
*
|
||||
* @param params
|
||||
* the parameters
|
||||
*/
|
||||
public SizeMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final List<String> a, final List<String> b, final Config conf) {
|
||||
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1.0;
|
||||
|
||||
return a.size() == b.size() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.tree.support.AbstractSortedComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class SortedJaroWinkler.
|
||||
*/
|
||||
@ComparatorClass("sortedJaroWinkler")
|
||||
public class SortedJaroWinkler extends AbstractSortedComparator {
|
||||
|
||||
public SortedJaroWinkler(Map<String,String> params){
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new sorted jaro winkler.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
*/
|
||||
public SortedJaroWinkler(final double weight) {
|
||||
super(weight, new com.wcohen.ss.JaroWinkler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new sorted jaro winkler.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
* @param ssalgo
|
||||
* the ssalgo
|
||||
*/
|
||||
protected SortedJaroWinkler(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.DistanceAlgo#getWeight()
|
||||
*/
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.SecondStringDistanceAlgo#normalize(double)
|
||||
*/
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.tree.support.AbstractSortedComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class SortedJaroWinkler.
|
||||
*/
|
||||
@ComparatorClass("sortedLevel2JaroWinkler")
|
||||
public class SortedLevel2JaroWinkler extends AbstractSortedComparator {
|
||||
|
||||
/**
|
||||
* Instantiates a new sorted jaro winkler.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
*/
|
||||
public SortedLevel2JaroWinkler(final double weight) {
|
||||
super(weight, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
public SortedLevel2JaroWinkler(final Map<String, String> params){
|
||||
super(params, new com.wcohen.ss.Level2JaroWinkler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new sorted jaro winkler.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
* @param ssalgo
|
||||
* the ssalgo
|
||||
*/
|
||||
protected SortedLevel2JaroWinkler(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.DistanceAlgo#getWeight()
|
||||
*/
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.SecondStringDistanceAlgo#normalize(double)
|
||||
*/
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractComparator;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class Contains match
|
||||
*
|
||||
* @author miconis
|
||||
* */
|
||||
@ComparatorClass("stringContainsMatch")
|
||||
public class StringContainsMatch extends AbstractStringComparator {
|
||||
|
||||
private Map<String, String> params;
|
||||
|
||||
private boolean CASE_SENSITIVE;
|
||||
private String STRING;
|
||||
private String AGGREGATOR;
|
||||
|
||||
public StringContainsMatch(Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
|
||||
//read parameters
|
||||
CASE_SENSITIVE = Boolean.parseBoolean(params.getOrDefault("caseSensitive", "false"));
|
||||
STRING = params.get("string");
|
||||
AGGREGATOR = params.get("aggregator");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
|
||||
String ca = a;
|
||||
String cb = b;
|
||||
if (!CASE_SENSITIVE) {
|
||||
ca = a.toLowerCase();
|
||||
cb = b.toLowerCase();
|
||||
STRING = STRING.toLowerCase();
|
||||
}
|
||||
|
||||
switch(AGGREGATOR) {
|
||||
case "AND":
|
||||
if(ca.contains(STRING) && cb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
case "OR":
|
||||
if(ca.contains(STRING) || cb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
case "XOR":
|
||||
if(ca.contains(STRING) ^ cb.contains(STRING))
|
||||
return 1.0;
|
||||
break;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractListComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ComparatorClass("stringListMatch")
|
||||
public class StringListMatch extends AbstractListComparator {
|
||||
|
||||
private static final Log log = LogFactory.getLog(StringListMatch.class);
|
||||
private Map<String, String> params;
|
||||
|
||||
final private String TYPE; //percentage or count
|
||||
|
||||
public StringListMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
this.params = params;
|
||||
|
||||
TYPE = params.getOrDefault("type", "percentage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final List<String> a, final List<String> b, final Config conf) {
|
||||
|
||||
final Set<String> pa = new HashSet<>(a);
|
||||
final Set<String> pb = new HashSet<>(b);
|
||||
|
||||
if (pa.isEmpty() || pb.isEmpty()) {
|
||||
return -1; //return undefined if one of the two lists is empty
|
||||
}
|
||||
|
||||
int incommon = Sets.intersection(pa, pb).size();
|
||||
int simDiff = Sets.symmetricDifference(pa, pb).size();
|
||||
|
||||
if (incommon + simDiff == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if(TYPE.equals("percentage"))
|
||||
return (double)incommon / (incommon + simDiff);
|
||||
else
|
||||
return incommon;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class SubStringLevenstein.
|
||||
*/
|
||||
@ComparatorClass("subStringLevenstein")
|
||||
public class SubStringLevenstein extends AbstractStringComparator {
|
||||
|
||||
/**
|
||||
* The limit.
|
||||
*/
|
||||
protected int limit;
|
||||
|
||||
/**
|
||||
* Instantiates a new sub string levenstein.
|
||||
*
|
||||
* @param w the w
|
||||
*/
|
||||
public SubStringLevenstein(final double w) {
|
||||
super(w, new com.wcohen.ss.Levenstein());
|
||||
}
|
||||
|
||||
public SubStringLevenstein(Map<String, String> params) {
|
||||
super(params, new com.wcohen.ss.Levenstein());
|
||||
this.limit = Integer.parseInt(params.getOrDefault("limit", "1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new sub string levenstein.
|
||||
*
|
||||
* @param w the w
|
||||
* @param limit the limit
|
||||
*/
|
||||
public SubStringLevenstein(final double w, final int limit) {
|
||||
super(w, new com.wcohen.ss.Levenstein());
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new sub string levenstein.
|
||||
*
|
||||
* @param w the w
|
||||
* @param limit the limit
|
||||
* @param ssalgo the ssalgo
|
||||
*/
|
||||
protected SubStringLevenstein(final double w, final int limit, final AbstractStringDistance ssalgo) {
|
||||
super(w, ssalgo);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.SecondStringDistanceAlgo#compare(eu.dnetlib.pace.model.Field, eu.dnetlib.pace.model.Field)
|
||||
*/
|
||||
@Override
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
return distance(StringUtils.left(a, limit), StringUtils.left(b, limit), conf);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.DistanceAlgo#getWeight()
|
||||
*/
|
||||
@Override
|
||||
public double getWeight() {
|
||||
return super.weight;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see eu.dnetlib.pace.compare.SecondStringDistanceAlgo#normalize(double)
|
||||
*/
|
||||
@Override
|
||||
protected double normalize(final double d) {
|
||||
return 1 / Math.pow(Math.abs(d) + 1, 0.1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Returns true if the titles in the given documents contains the same numbers, false otherwise.
|
||||
*
|
||||
* @author claudio
|
||||
*
|
||||
*/
|
||||
@ComparatorClass("titleVersionMatch")
|
||||
public class TitleVersionMatch extends AbstractStringComparator {
|
||||
|
||||
public TitleVersionMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final String valueA, final String valueB, final Config conf) {
|
||||
if (valueA.isEmpty() || valueB.isEmpty())
|
||||
return -1;
|
||||
|
||||
return notNull(valueA) && notNull(valueB) && !checkNumbers(valueA, valueB) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ":" + super.toString();
|
||||
}
|
||||
|
||||
protected String toString(final Object object) {
|
||||
return toFirstString(object);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
@ComparatorClass("urlMatcher")
|
||||
public class UrlMatcher extends Levenstein {
|
||||
|
||||
private Map<String, String> params;
|
||||
|
||||
public UrlMatcher(Map<String, String> params){
|
||||
super(params);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public UrlMatcher(double weight, Map<String, String> params) {
|
||||
super(weight);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public void setParams(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double distance(String a, String b, final Config conf) {
|
||||
final URL urlA = asUrl(a);
|
||||
final URL urlB = asUrl(b);
|
||||
|
||||
if (!urlA.getHost().equalsIgnoreCase(urlB.getHost())) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Double hostW = Double.parseDouble(params.getOrDefault("host", "0.5"));
|
||||
Double pathW = Double.parseDouble(params.getOrDefault("path", "0.5"));
|
||||
|
||||
if (StringUtils.isBlank(urlA.getPath()) || StringUtils.isBlank(urlB.getPath())) {
|
||||
return hostW * 0.5;
|
||||
}
|
||||
|
||||
return hostW + pathW * super.distance(urlA.getPath(), urlB.getPath(), conf);
|
||||
}
|
||||
|
||||
private URL asUrl(final String value) {
|
||||
try {
|
||||
return new URL(value);
|
||||
} catch (MalformedURLException e) {
|
||||
// should not happen as checked by pace typing
|
||||
throw new IllegalStateException("invalid URL: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
protected String toString(final Object object) {
|
||||
return toFirstString(object);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package eu.dnetlib.pace.tree;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.tree.support.AbstractStringComparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Returns true if the year of the date field in the given documents are the same, false when any of the two is invalid or it's missing.
|
||||
*
|
||||
* @author claudio
|
||||
*/
|
||||
@ComparatorClass("yearMatch")
|
||||
public class YearMatch extends AbstractStringComparator {
|
||||
|
||||
private int limit = 4;
|
||||
|
||||
public YearMatch(final Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(final String a, final String b, final Config conf) {
|
||||
final String valueA = getNumbers(getFirstValue(a));
|
||||
final String valueB = getNumbers(getFirstValue(b));
|
||||
|
||||
if (valueA.isEmpty() || valueB.isEmpty())
|
||||
return -1;
|
||||
|
||||
final boolean lengthMatch = checkLength(valueA) && checkLength(valueB);
|
||||
final boolean onemissing = valueA.isEmpty() || valueB.isEmpty();
|
||||
|
||||
return lengthMatch && valueA.equals(valueB) || onemissing ? 1 : 0;
|
||||
}
|
||||
|
||||
protected boolean checkLength(final String s) {
|
||||
return s.length() == limit;
|
||||
}
|
||||
|
||||
protected String getFirstValue(final String value) {
|
||||
return (value != null) && !value.isEmpty() ? StringUtils.left(value, limit) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ":" + super.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.common.AbstractPaceFunctions;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractComparator<T> extends AbstractPaceFunctions implements Comparator<T> {
|
||||
|
||||
/** The ssalgo. */
|
||||
protected AbstractStringDistance ssalgo;
|
||||
|
||||
/** The weight. */
|
||||
protected double weight = 0.0;
|
||||
|
||||
private Map<String, String> params;
|
||||
|
||||
protected AbstractComparator(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
protected AbstractComparator(Map<String, String> params, final AbstractStringDistance ssalgo){
|
||||
this.params = params;
|
||||
this.weight = 1.0;
|
||||
this.ssalgo = ssalgo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new second string compare algo.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
* @param ssalgo
|
||||
* the ssalgo
|
||||
*/
|
||||
protected AbstractComparator(final double weight, final AbstractStringDistance ssalgo) {
|
||||
this.ssalgo = ssalgo;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
protected AbstractComparator(final AbstractStringDistance ssalgo){
|
||||
this.ssalgo = ssalgo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize.
|
||||
*
|
||||
* @param d
|
||||
* the d
|
||||
* @return the double
|
||||
*/
|
||||
protected double normalize(double d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Distance.
|
||||
*
|
||||
* @param a
|
||||
* the a
|
||||
* @param b
|
||||
* the b
|
||||
* @return the double
|
||||
*/
|
||||
|
||||
protected double distance(final String a, final String b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty()) {
|
||||
return -1; //return -1 if a field is missing
|
||||
}
|
||||
double score = ssalgo.score(a, b);
|
||||
return normalize(score);
|
||||
}
|
||||
|
||||
protected double compare(final String a, final String b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1;
|
||||
return distance(a, b, conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given argument to a List of Strings
|
||||
*
|
||||
* @param object
|
||||
* function argument
|
||||
* @return the list
|
||||
*/
|
||||
protected List<String> toList(final Object object) {
|
||||
if (object instanceof List) {
|
||||
return (List<String>)object;
|
||||
}
|
||||
|
||||
return Lists.newArrayList(object.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given argument to a String
|
||||
*
|
||||
* @param object
|
||||
* function argument
|
||||
* @return the list
|
||||
*/
|
||||
protected String toString(final Object object) {
|
||||
if (object instanceof List) {
|
||||
List<String> l = (List<String>) object;
|
||||
return Joiner.on(" ").join(l);
|
||||
}
|
||||
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
protected String toFirstString(final Object object) {
|
||||
if (object instanceof List) {
|
||||
List<String> l = (List<String>) object;
|
||||
return l.isEmpty() ? "" : l.get(0);
|
||||
}
|
||||
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
|
||||
public double getWeight(){
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.config.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
abstract public class AbstractListComparator extends AbstractComparator<List<String>>{
|
||||
protected AbstractListComparator(Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
protected AbstractListComparator(Map<String, String> params, AbstractStringDistance ssalgo) {
|
||||
super(params, ssalgo);
|
||||
}
|
||||
|
||||
protected AbstractListComparator(double weight, AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
protected AbstractListComparator(AbstractStringDistance ssalgo) {
|
||||
super(ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(Object a, Object b, Config conf) {
|
||||
return compare(toList(a), toList(b), conf);
|
||||
}
|
||||
|
||||
public double compare(final List<String> a, final List<String> b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1;
|
||||
|
||||
return distance(concat(a), concat(b), conf);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractSortedComparator extends AbstractListComparator {
|
||||
|
||||
/**
|
||||
* Instantiates a new sorted second string compare algo.
|
||||
*
|
||||
* @param weight
|
||||
* the weight
|
||||
* @param ssalgo
|
||||
* the ssalgo
|
||||
*/
|
||||
protected AbstractSortedComparator(final double weight, final AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
protected AbstractSortedComparator(final Map<String, String> params, final AbstractStringDistance ssalgo){
|
||||
super(Double.parseDouble(params.get("weight")), ssalgo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> toList(final Object object) {
|
||||
if (object instanceof List) {
|
||||
List<String> fl = (List<String>) object;
|
||||
List<String> values = Lists.newArrayList(fl);
|
||||
Collections.sort(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
return Lists.newArrayList(object.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.wcohen.ss.AbstractStringDistance;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractStringComparator extends AbstractComparator<String>{
|
||||
protected AbstractStringComparator(Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
protected AbstractStringComparator(Map<String, String> params, AbstractStringDistance ssalgo) {
|
||||
super(params, ssalgo);
|
||||
}
|
||||
|
||||
protected AbstractStringComparator(double weight, AbstractStringDistance ssalgo) {
|
||||
super(weight, ssalgo);
|
||||
}
|
||||
|
||||
protected AbstractStringComparator(AbstractStringDistance ssalgo) {
|
||||
super(ssalgo);
|
||||
}
|
||||
|
||||
public double distance(final String a, final String b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty()) {
|
||||
return -1; //return -1 if a field is missing
|
||||
}
|
||||
double score = ssalgo.score(a, b);
|
||||
return normalize(score);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double compare(Object a, Object b, Config conf) {
|
||||
return compare(toString(a), toString(b), conf);
|
||||
}
|
||||
|
||||
public double compare(final String a, final String b, final Config conf) {
|
||||
if (a.isEmpty() || b.isEmpty())
|
||||
return -1;
|
||||
return distance(a, b, conf);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
|
||||
public enum AggType {
|
||||
|
||||
W_MEAN, //weighted mean
|
||||
AVG, //average
|
||||
SUM,
|
||||
MAX,
|
||||
MIN,
|
||||
AND, //used for necessary conditions
|
||||
OR; //used for sufficient conditions
|
||||
|
||||
public static AggType getEnum(String value) {
|
||||
|
||||
try {
|
||||
return AggType.valueOf(value);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new PaceException("Undefined aggregation type", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
|
||||
public interface Comparator<T> {
|
||||
|
||||
/*
|
||||
* return : -1 -> can't decide (i.e. missing field)
|
||||
* >0 -> similarity degree (depends on the algorithm)
|
||||
* */
|
||||
public double compare(Object a, Object b, Config conf);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ComparatorClass {
|
||||
|
||||
public String value();
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The class that defines the configuration of each field in the decision tree.
|
||||
* */
|
||||
public class FieldConf implements Serializable {
|
||||
|
||||
private String field; //name of the field on which apply the comparator
|
||||
private String comparator; //comparator name
|
||||
private double weight = 1.0; //weight for the field (to be used in the aggregation)
|
||||
private Map<String,String> params; //parameters
|
||||
|
||||
private boolean countIfUndefined;
|
||||
|
||||
public boolean isCountIfUndefined() {
|
||||
return countIfUndefined;
|
||||
}
|
||||
|
||||
public void setCountIfUndefined(boolean countIfUndefined) {
|
||||
this.countIfUndefined = countIfUndefined;
|
||||
}
|
||||
|
||||
public FieldConf() {
|
||||
}
|
||||
|
||||
public FieldConf(String field, String comparator, double weight, Map<String, String> params, boolean countIfUndefined) {
|
||||
this.field = field;
|
||||
this.comparator = comparator;
|
||||
this.weight = weight;
|
||||
this.params = params;
|
||||
this.countIfUndefined = countIfUndefined;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public String getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
public void setComparator(String comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
public double getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(double weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("Impossible to convert to JSON: ", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The class that contains the result of each comparison in the decision tree
|
||||
* */
|
||||
public class FieldStats implements Serializable {
|
||||
|
||||
private double weight; //weight for the field (to be used in the aggregation)
|
||||
private double threshold; //threshold for the field (to be used in some kind of aggregations)
|
||||
private double result; //the result of the comparison
|
||||
private Object a;
|
||||
private Object b;
|
||||
|
||||
private boolean countIfUndefined;
|
||||
|
||||
public FieldStats(double weight, double threshold, double result, boolean countIfUndefined, Object a, Object b) {
|
||||
this.weight = weight;
|
||||
this.threshold = threshold;
|
||||
this.result = result;
|
||||
this.countIfUndefined = countIfUndefined;
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public double getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(double threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public double getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(double weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public double getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(double result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public boolean isCountIfUndefined() {
|
||||
return countIfUndefined;
|
||||
}
|
||||
|
||||
public void setCountIfUndefined(boolean countIfUndefined) {
|
||||
this.countIfUndefined = countIfUndefined;
|
||||
}
|
||||
|
||||
public Object getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public void setA(Object a) {
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public Object getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setB(Object b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("Impossible to convert to JSON: ", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
public enum MatchType {
|
||||
|
||||
MATCH,
|
||||
NO_MATCH,
|
||||
UNDEFINED;
|
||||
|
||||
public static MatchType parse(String value) {
|
||||
|
||||
if (MATCH.name().equals(value)) {
|
||||
return MATCH;
|
||||
} else if (NO_MATCH.name().equals(value)) {
|
||||
return NO_MATCH;
|
||||
} else {
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
// try {
|
||||
// return MatchType.valueOf(value);
|
||||
// }
|
||||
// catch (IllegalArgumentException e) {
|
||||
// return MatchType.UNDEFINED; //return UNDEFINED if the enum is not parsable
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.config.PaceConfig;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
import org.apache.spark.sql.Row;
|
||||
import org.apache.spark.sql.types.ArrayType;
|
||||
import org.apache.spark.sql.types.DataType;
|
||||
import org.apache.spark.sql.types.StringType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class TreeNodeDef implements Serializable {
|
||||
|
||||
final static String CROSS_COMPARE = "crossCompare";
|
||||
|
||||
private List<FieldConf> fields;
|
||||
private AggType aggregation;
|
||||
|
||||
private double threshold;
|
||||
|
||||
private String positive;
|
||||
private String negative;
|
||||
private String undefined;
|
||||
|
||||
boolean ignoreUndefined;
|
||||
|
||||
public TreeNodeDef(List<FieldConf> fields, AggType aggregation, double threshold, String positive, String negative, String undefined, boolean ignoreUndefined) {
|
||||
this.fields = fields;
|
||||
this.aggregation = aggregation;
|
||||
this.threshold = threshold;
|
||||
this.positive = positive;
|
||||
this.negative = negative;
|
||||
this.undefined = undefined;
|
||||
this.ignoreUndefined = ignoreUndefined;
|
||||
}
|
||||
|
||||
public TreeNodeDef() {}
|
||||
|
||||
//function for the evaluation of the node
|
||||
public TreeNodeStats evaluate(Row doc1, Row doc2, Config conf) {
|
||||
|
||||
TreeNodeStats stats = new TreeNodeStats();
|
||||
|
||||
//for each field in the node, it computes the
|
||||
for (FieldConf fieldConf : fields) {
|
||||
double weight = fieldConf.getWeight();
|
||||
double result;
|
||||
|
||||
Object value1 = getJavaValue(doc1,fieldConf.getField());
|
||||
Object value2 = getJavaValue(doc2,fieldConf.getField());
|
||||
|
||||
|
||||
//if the param specifies a cross comparison (i.e. compare elements from different fields), compute the result for both sides and return the maximum
|
||||
String crossField = fieldConf.getParams().get(CROSS_COMPARE);
|
||||
if (crossField != null) {
|
||||
double result1 = comparator(fieldConf).compare(value1, getJavaValue(doc2,crossField), conf);
|
||||
double result2 = comparator(fieldConf).compare(getJavaValue(doc1,crossField), value2, conf);
|
||||
result = Math.max(result1,result2);
|
||||
}
|
||||
else {
|
||||
result = comparator(fieldConf).compare(value1, value2, conf);
|
||||
}
|
||||
|
||||
stats.addFieldStats(
|
||||
fieldConf.getComparator() + " on " + fieldConf.getField() + " " + fields.indexOf(fieldConf),
|
||||
new FieldStats(
|
||||
weight,
|
||||
Double.parseDouble(fieldConf.getParams().getOrDefault("threshold", "1.0")),
|
||||
result,
|
||||
fieldConf.isCountIfUndefined(),
|
||||
value1,
|
||||
value2
|
||||
));
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
public Object getJavaValue(Row row, String name) {
|
||||
int pos = row.fieldIndex(name);
|
||||
if (pos >= 0) {
|
||||
DataType dt = row.schema().fields()[pos].dataType();
|
||||
if (dt instanceof StringType) {
|
||||
return row.getString(pos);
|
||||
} else if (dt instanceof ArrayType) {
|
||||
return row.getList(pos);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Comparator comparator(final FieldConf field){
|
||||
|
||||
return PaceConfig.resolver.getComparator(field.getComparator(), field.getParams());
|
||||
}
|
||||
|
||||
public List<FieldConf> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<FieldConf> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public AggType getAggregation() {
|
||||
return aggregation;
|
||||
}
|
||||
|
||||
public void setAggregation(AggType aggregation) {
|
||||
this.aggregation = aggregation;
|
||||
}
|
||||
|
||||
public double getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(double threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public String getPositive() {
|
||||
return positive;
|
||||
}
|
||||
|
||||
public void setPositive(String positive) {
|
||||
this.positive = positive;
|
||||
}
|
||||
|
||||
public String getNegative() {
|
||||
return negative;
|
||||
}
|
||||
|
||||
public void setNegative(String negative) {
|
||||
this.negative = negative;
|
||||
}
|
||||
|
||||
public String getUndefined() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public void setUndefined(String undefined) {
|
||||
this.undefined = undefined;
|
||||
}
|
||||
|
||||
public boolean isIgnoreUndefined() {
|
||||
return ignoreUndefined;
|
||||
}
|
||||
|
||||
public void setIgnoreUndefined(boolean ignoreUndefined) {
|
||||
this.ignoreUndefined = ignoreUndefined;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("Impossible to convert to JSON: ", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TreeNodeStats implements Serializable {
|
||||
|
||||
private Map<String, FieldStats> results; //this is an accumulator for the results of the node
|
||||
|
||||
public TreeNodeStats(){
|
||||
this.results = new HashMap<>();
|
||||
}
|
||||
|
||||
public Map<String, FieldStats> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public void addFieldStats(String id, FieldStats fieldStats){
|
||||
this.results.put(id, fieldStats);
|
||||
}
|
||||
|
||||
public int fieldsCount(){
|
||||
return this.results.size();
|
||||
}
|
||||
|
||||
public int undefinedCount(){
|
||||
int undefinedCount = 0;
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult() == -1)
|
||||
undefinedCount ++;
|
||||
}
|
||||
return undefinedCount;
|
||||
}
|
||||
|
||||
public double scoreSum(){
|
||||
double scoreSum = 0.0;
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult()>=0.0) {
|
||||
scoreSum += fs.getResult();
|
||||
}
|
||||
}
|
||||
return scoreSum;
|
||||
}
|
||||
|
||||
//return the sum of the weights without considering the fields with countIfMissing=false && result=-1
|
||||
public double weightSum(){
|
||||
double weightSum = 0.0;
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult()>=0.0 || (fs.getResult()<0.0 && fs.isCountIfUndefined())) {
|
||||
weightSum += fs.getWeight();
|
||||
}
|
||||
}
|
||||
return weightSum;
|
||||
}
|
||||
|
||||
public double weightedScoreSum(){
|
||||
double weightedScoreSum = 0.0;
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult()>=0.0) {
|
||||
weightedScoreSum += fs.getResult()*fs.getWeight();
|
||||
}
|
||||
}
|
||||
return weightedScoreSum;
|
||||
}
|
||||
|
||||
public double max(){
|
||||
double max = -1.0;
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult()>max)
|
||||
max = fs.getResult();
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public double min(){
|
||||
double min = 100.0; //random high value
|
||||
for(FieldStats fs: this.results.values()){
|
||||
if(fs.getResult()<min) {
|
||||
if (fs.getResult()>=0.0 || (fs.getResult() == -1 && fs.isCountIfUndefined()))
|
||||
min = fs.getResult();
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
//if at least one is true, return 1.0
|
||||
public double or(){
|
||||
for (FieldStats fieldStats : this.results.values()) {
|
||||
if (fieldStats.getResult() >= fieldStats.getThreshold())
|
||||
return 1.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//if at least one is false, return 0.0
|
||||
public double and() {
|
||||
for (FieldStats fieldStats : this.results.values()) {
|
||||
|
||||
if (fieldStats.getResult() == -1) {
|
||||
if (fieldStats.isCountIfUndefined())
|
||||
return 0.0;
|
||||
}
|
||||
else {
|
||||
if (fieldStats.getResult() < fieldStats.getThreshold())
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public double getFinalScore(AggType aggregation){
|
||||
|
||||
switch (aggregation){
|
||||
case AVG:
|
||||
return scoreSum()/fieldsCount();
|
||||
case SUM:
|
||||
return scoreSum();
|
||||
case MAX:
|
||||
return max();
|
||||
case MIN:
|
||||
return min();
|
||||
case W_MEAN:
|
||||
return weightedScoreSum()/weightSum();
|
||||
case OR:
|
||||
return or();
|
||||
case AND:
|
||||
return and();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import eu.dnetlib.pace.config.Config;
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.spark.sql.Row;
|
||||
|
||||
|
||||
/**
|
||||
* The compare between two documents is given by the weighted mean of the field distances
|
||||
*/
|
||||
public class TreeProcessor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TreeProcessor.class);
|
||||
|
||||
private Config config;
|
||||
|
||||
public TreeProcessor(final Config config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
// row based copies
|
||||
|
||||
public boolean compare(final Row a, final Row b) {
|
||||
//evaluate the decision tree
|
||||
return evaluateTree(a, b).getResult() == MatchType.MATCH;
|
||||
}
|
||||
|
||||
public TreeStats evaluateTree(final Row doc1, final Row doc2){
|
||||
|
||||
TreeStats treeStats = new TreeStats();
|
||||
|
||||
String nextNodeName = "start";
|
||||
|
||||
do {
|
||||
|
||||
TreeNodeDef currentNode = config.decisionTree().get(nextNodeName);
|
||||
//throw an exception if the node doesn't exist
|
||||
if (currentNode == null)
|
||||
throw new PaceException("Missing tree node: " + nextNodeName);
|
||||
|
||||
TreeNodeStats stats = currentNode.evaluate(doc1, doc2, config);
|
||||
treeStats.addNodeStats(nextNodeName, stats);
|
||||
|
||||
//if ignoreUndefined=false the miss is considered as undefined
|
||||
if (!currentNode.isIgnoreUndefined() && stats.undefinedCount()>0) {
|
||||
nextNodeName = currentNode.getUndefined();
|
||||
}
|
||||
//if ignoreUndefined=true the miss is ignored and the score computed anyway
|
||||
else if (stats.getFinalScore(currentNode.getAggregation()) >= currentNode.getThreshold()) {
|
||||
nextNodeName = currentNode.getPositive();
|
||||
}
|
||||
else {
|
||||
nextNodeName = currentNode.getNegative();
|
||||
}
|
||||
|
||||
} while (MatchType.parse(nextNodeName)==MatchType.UNDEFINED);
|
||||
|
||||
treeStats.setResult(MatchType.parse(nextNodeName));
|
||||
return treeStats;
|
||||
}
|
||||
|
||||
public double computeScore(final Row doc1, final Row doc2) {
|
||||
String nextNodeName = "start";
|
||||
double score = 0.0;
|
||||
|
||||
do {
|
||||
|
||||
TreeNodeDef currentNode = config.decisionTree().get(nextNodeName);
|
||||
//throw an exception if the node doesn't exist
|
||||
if (currentNode == null)
|
||||
throw new PaceException("The Tree Node doesn't exist: " + nextNodeName);
|
||||
|
||||
TreeNodeStats stats = currentNode.evaluate(doc1, doc2, config);
|
||||
|
||||
score = stats.getFinalScore(currentNode.getAggregation());
|
||||
//if ignoreUndefined=false the miss is considered as undefined
|
||||
if (!currentNode.isIgnoreUndefined() && stats.undefinedCount()>0) {
|
||||
nextNodeName = currentNode.getUndefined();
|
||||
}
|
||||
//if ignoreUndefined=true the miss is ignored and the score computed anyway
|
||||
else if (stats.getFinalScore(currentNode.getAggregation()) >= currentNode.getThreshold()) {
|
||||
nextNodeName = currentNode.getPositive();
|
||||
}
|
||||
else {
|
||||
nextNodeName = currentNode.getNegative();
|
||||
}
|
||||
} while (MatchType.parse(nextNodeName)==MatchType.UNDEFINED);
|
||||
|
||||
return score;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package eu.dnetlib.pace.tree.support;
|
||||
|
||||
import eu.dnetlib.pace.util.PaceException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TreeStats {
|
||||
|
||||
//<layer_id, <field:comparator, result>>
|
||||
Map<String, TreeNodeStats> stats;
|
||||
MatchType result;
|
||||
|
||||
public TreeStats(){
|
||||
this.stats = new HashMap<>();
|
||||
this.result = MatchType.NO_MATCH;
|
||||
}
|
||||
|
||||
public MatchType getResult(){
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public void setResult(MatchType result){
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Map<String, TreeNodeStats> getStats() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public void setStats(Map<String, TreeNodeStats> stats) {
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
public void addNodeStats(String layerID, TreeNodeStats treeNodeStats){
|
||||
this.stats.put(layerID, treeNodeStats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
try {
|
||||
return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
} catch (IOException e) {
|
||||
throw new PaceException("Impossible to convert to JSON: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
import eu.dnetlib.pace.config.DedupConfig;
|
||||
import eu.dnetlib.pace.config.WfConfig;
|
||||
import eu.dnetlib.pace.tree.support.TreeProcessor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.spark.sql.Row;
|
||||
import org.apache.spark.sql.types.ArrayType;
|
||||
import org.apache.spark.sql.types.DataType;
|
||||
import org.apache.spark.sql.types.StringType;
|
||||
import org.apache.spark.sql.types.StructType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockProcessor {
|
||||
|
||||
public static final List<String> accumulators= new ArrayList<>();
|
||||
|
||||
private static final Log log = LogFactory.getLog(BlockProcessor.class);
|
||||
|
||||
private DedupConfig dedupConf;
|
||||
|
||||
private final int identifierFieldPos;
|
||||
private final int orderFieldPos;
|
||||
|
||||
public static void constructAccumulator( final DedupConfig dedupConf) {
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), "records per hash key = 1"));
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), "missing " + dedupConf.getWf().getOrderField()));
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), String.format("Skipped records for count(%s) >= %s", dedupConf.getWf().getOrderField(), dedupConf.getWf().getGroupMaxSize())));
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), "skip list"));
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), "dedupSimilarity (x2)"));
|
||||
accumulators.add(String.format("%s::%s",dedupConf.getWf().getEntityType(), "d < " + dedupConf.getWf().getThreshold()));
|
||||
}
|
||||
|
||||
public BlockProcessor(DedupConfig dedupConf, int identifierFieldPos, int orderFieldPos) {
|
||||
this.dedupConf = dedupConf;
|
||||
this.identifierFieldPos = identifierFieldPos;
|
||||
this.orderFieldPos = orderFieldPos;
|
||||
}
|
||||
|
||||
public void processSortedRows(final Collection<Row> documents, final Reporter context) {
|
||||
if (documents.size() > 1) {
|
||||
// log.info("reducing key: '" + key + "' records: " + q.size());
|
||||
processRows(documents, context);
|
||||
|
||||
} else {
|
||||
context.incrementCounter(dedupConf.getWf().getEntityType(), "records per hash key = 1", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processRows(final Collection<Row> queue, final Reporter context) {
|
||||
|
||||
Iterator<Row> it = queue.iterator();
|
||||
while (it.hasNext()) {
|
||||
|
||||
final Row pivot = it.next();
|
||||
it.remove();
|
||||
|
||||
|
||||
final String idPivot = pivot.getString(identifierFieldPos); //identifier
|
||||
final Object fieldsPivot = getJavaValue(pivot, orderFieldPos);
|
||||
final String fieldPivot = (fieldsPivot == null) ? "" : fieldsPivot.toString();
|
||||
final WfConfig wf = dedupConf.getWf();
|
||||
|
||||
if (fieldPivot != null) {
|
||||
int i = 0;
|
||||
for (final Row curr : queue) {
|
||||
final String idCurr = curr.getString(identifierFieldPos); //identifier
|
||||
|
||||
if (mustSkip(idCurr)) {
|
||||
|
||||
context.incrementCounter(wf.getEntityType(), "skip list", 1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > wf.getSlidingWindowSize()) {
|
||||
break;
|
||||
}
|
||||
|
||||
final Object fieldsCurr = getJavaValue(curr, orderFieldPos);
|
||||
final String fieldCurr = (fieldsCurr == null) ? null : fieldsCurr.toString();
|
||||
|
||||
if (!idCurr.equals(idPivot) && (fieldCurr != null)) {
|
||||
|
||||
final TreeProcessor treeProcessor = new TreeProcessor(dedupConf);
|
||||
|
||||
emitOutput(treeProcessor.compare(pivot, curr), idPivot, idCurr, context);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object getJavaValue(Row row, int pos) {
|
||||
DataType dt = row.schema().fields()[pos].dataType();
|
||||
if (dt instanceof StringType) {
|
||||
return row.getString(pos);
|
||||
} else if (dt instanceof ArrayType) {
|
||||
return row.getList(pos);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void emitOutput(final boolean result, final String idPivot, final String idCurr, final Reporter context) {
|
||||
|
||||
if (result) {
|
||||
writeSimilarity(context, idPivot, idCurr);
|
||||
context.incrementCounter(dedupConf.getWf().getEntityType(), "dedupSimilarity (x2)", 1);
|
||||
} else {
|
||||
context.incrementCounter(dedupConf.getWf().getEntityType(), "d < " + dedupConf.getWf().getThreshold(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mustSkip(final String idPivot) {
|
||||
return dedupConf.getWf().getSkipList().contains(getNsPrefix(idPivot));
|
||||
}
|
||||
|
||||
private String getNsPrefix(final String id) {
|
||||
return StringUtils.substringBetween(id, "|", "::");
|
||||
}
|
||||
|
||||
private void writeSimilarity(final Reporter context, final String from, final String to) {
|
||||
final String type = dedupConf.getWf().getEntityType();
|
||||
|
||||
context.emit(type, from, to);
|
||||
context.emit(type, to, from);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
|
||||
public class Capitalise implements Function<String, String> {
|
||||
|
||||
private final char[] DELIM = {' ', '-'};
|
||||
|
||||
@Override
|
||||
public String apply(final String s) {
|
||||
return WordUtils.capitalize(s.toLowerCase(), DELIM);
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class DotAbbreviations implements Function<String, String> {
|
||||
@Override
|
||||
public String apply(String s) {
|
||||
return s.length() == 1 ? s + "." : s;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,117 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import com.jayway.jsonpath.Option;
|
||||
import eu.dnetlib.pace.config.DedupConfig;
|
||||
import eu.dnetlib.pace.config.Type;
|
||||
import eu.dnetlib.pace.model.*;
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapDocumentUtil {
|
||||
|
||||
public static final String URL_REGEX = "^(http|https|ftp)\\://.*";
|
||||
public static Predicate<String> urlFilter = s -> s.trim().matches(URL_REGEX);
|
||||
|
||||
public static List<String> getJPathList(String path, String json, Type type) {
|
||||
if (type == Type.List)
|
||||
return JsonPath.using(Configuration.defaultConfiguration().addOptions(Option.ALWAYS_RETURN_LIST, Option.SUPPRESS_EXCEPTIONS)).parse(json).read(path);
|
||||
Object jresult;
|
||||
List<String> result = new ArrayList<>();
|
||||
try {
|
||||
jresult = JsonPath.read(json, path);
|
||||
} catch (Throwable e) {
|
||||
return result;
|
||||
}
|
||||
if (jresult instanceof JSONArray) {
|
||||
|
||||
((JSONArray) jresult).forEach(it -> {
|
||||
|
||||
try {
|
||||
result.add(new ObjectMapper().writeValueAsString(it));
|
||||
} catch (JsonProcessingException e) {
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (jresult instanceof LinkedHashMap) {
|
||||
try {
|
||||
result.add(new ObjectMapper().writeValueAsString(jresult));
|
||||
} catch (JsonProcessingException e) {
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (jresult instanceof String) {
|
||||
result.add((String) jresult);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String getJPathString(final String jsonPath, final String json) {
|
||||
try {
|
||||
Object o = JsonPath.read(json, jsonPath);
|
||||
if (o instanceof String)
|
||||
return (String)o;
|
||||
if (o instanceof JSONArray && ((JSONArray)o).size()>0)
|
||||
return (String)((JSONArray)o).get(0);
|
||||
return "";
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static double[] getJPathArray(final String jsonPath, final String json) {
|
||||
try {
|
||||
Object o = JsonPath.read(json, jsonPath);
|
||||
if (o instanceof double[])
|
||||
return (double[]) o;
|
||||
if (o instanceof JSONArray) {
|
||||
Object[] objects = ((JSONArray) o).toArray();
|
||||
double[] array = new double[objects.length];
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] instanceof BigDecimal)
|
||||
array[i] = ((BigDecimal)objects[i]).doubleValue();
|
||||
else
|
||||
array[i] = (double) objects[i];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
return new double[0];
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new double[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String truncateValue(String value, int length) {
|
||||
if (value == null)
|
||||
return "";
|
||||
|
||||
if (length == -1 || length > value.length())
|
||||
return value;
|
||||
|
||||
return value.substring(0, length);
|
||||
}
|
||||
|
||||
public static List<String> truncateList(List<String> list, int size) {
|
||||
if (size == -1 || size > list.size())
|
||||
return list;
|
||||
|
||||
return list.subList(0, size);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
public class PaceException extends RuntimeException {
|
||||
|
||||
public PaceException(String s, Throwable e){
|
||||
super(s, e);
|
||||
}
|
||||
|
||||
public PaceException(String s){
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
import eu.dnetlib.pace.clustering.ClusteringClass;
|
||||
import eu.dnetlib.pace.clustering.ClusteringFunction;
|
||||
import eu.dnetlib.pace.tree.support.Comparator;
|
||||
import eu.dnetlib.pace.tree.support.ComparatorClass;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PaceResolver implements Serializable {
|
||||
|
||||
public static final Reflections CLUSTERING_RESOLVER = new Reflections("eu.dnetlib.pace.clustering");
|
||||
public static final Reflections COMPARATOR_RESOLVER = new Reflections("eu.dnetlib.pace.tree");
|
||||
|
||||
private final Map<String, Class<ClusteringFunction>> clusteringFunctions;
|
||||
private final Map<String, Class<Comparator>> comparators;
|
||||
|
||||
public PaceResolver() {
|
||||
|
||||
this.clusteringFunctions = CLUSTERING_RESOLVER.getTypesAnnotatedWith(ClusteringClass.class).stream()
|
||||
.filter(ClusteringFunction.class::isAssignableFrom)
|
||||
.collect(Collectors.toMap(cl -> cl.getAnnotation(ClusteringClass.class).value(), cl -> (Class<ClusteringFunction>)cl));
|
||||
|
||||
this.comparators = COMPARATOR_RESOLVER.getTypesAnnotatedWith(ComparatorClass.class).stream()
|
||||
.filter(Comparator.class::isAssignableFrom)
|
||||
.collect(Collectors.toMap(cl -> cl.getAnnotation(ComparatorClass.class).value(), cl -> (Class<Comparator>)cl));
|
||||
}
|
||||
|
||||
public ClusteringFunction getClusteringFunction(String name, Map<String, Integer> params) throws PaceException {
|
||||
try {
|
||||
return clusteringFunctions.get(name).getDeclaredConstructor(Map.class).newInstance(params);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new PaceException(name + " not found ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Comparator getComparator(String name, Map<String, String> params) throws PaceException {
|
||||
try {
|
||||
return comparators.get(name).getDeclaredConstructor(Map.class).newInstance(params);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | NullPointerException e) {
|
||||
throw new PaceException(name + " not found ", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package eu.dnetlib.pace.util;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface Reporter extends Serializable {
|
||||
|
||||
void incrementCounter(String counterGroup, String counterName, long delta);
|
||||
|
||||
void emit(String type, String from, String to);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"wf" : {
|
||||
"threshold" : "$threshold$",
|
||||
"dedupRun" : "$run$",
|
||||
"entityType" : "$entityType$",
|
||||
"subEntityType" : "$subEntityType$",
|
||||
"subEntityValue" : "$subEntityValue$",
|
||||
"orderField" : "$orderField$",
|
||||
"queueMaxSize" : "$queueMaxSize$",
|
||||
"groupMaxSize" : "$groupMaxSize$",
|
||||
"slidingWindowSize" : "$slidingWindowSize$",
|
||||
"rootBuilder" : [ $rootBuilder:{"$it$"};separator=", "$ ],
|
||||
"includeChildren" : "$includeChildren$",
|
||||
"configurationId" : "$configurationId$"
|
||||
},
|
||||
"pace" : {
|
||||
"clustering" : [
|
||||
],
|
||||
"sufficientConditions" : [
|
||||
],
|
||||
"necessaryConditions" : [
|
||||
],
|
||||
"model" : [
|
||||
],
|
||||
"blacklists" : { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
van
|
||||
der
|
||||
de
|
||||
dell
|
||||
sig
|
||||
mr
|
||||
mrs
|
|
@ -0,0 +1,620 @@
|
|||
a
|
||||
ab
|
||||
aber
|
||||
ach
|
||||
acht
|
||||
achte
|
||||
achten
|
||||
achter
|
||||
achtes
|
||||
ag
|
||||
alle
|
||||
allein
|
||||
allem
|
||||
aller
|
||||
allerdings
|
||||
alles
|
||||
allgemeinen
|
||||
als
|
||||
also
|
||||
am
|
||||
an
|
||||
ander
|
||||
andere
|
||||
anderem
|
||||
anderen
|
||||
anderer
|
||||
anderes
|
||||
anderm
|
||||
andern
|
||||
anderr
|
||||
anders
|
||||
au
|
||||
auch
|
||||
auf
|
||||
aus
|
||||
ausser
|
||||
ausserdem
|
||||
außer
|
||||
außerdem
|
||||
b
|
||||
bald
|
||||
bei
|
||||
beide
|
||||
beiden
|
||||
beim
|
||||
beispiel
|
||||
bekannt
|
||||
bereits
|
||||
besonders
|
||||
besser
|
||||
besten
|
||||
bin
|
||||
bis
|
||||
bisher
|
||||
bist
|
||||
c
|
||||
d
|
||||
d.h
|
||||
da
|
||||
dabei
|
||||
dadurch
|
||||
dafür
|
||||
dagegen
|
||||
daher
|
||||
dahin
|
||||
dahinter
|
||||
damals
|
||||
damit
|
||||
danach
|
||||
daneben
|
||||
dank
|
||||
dann
|
||||
daran
|
||||
darauf
|
||||
daraus
|
||||
darf
|
||||
darfst
|
||||
darin
|
||||
darum
|
||||
darunter
|
||||
darüber
|
||||
das
|
||||
dasein
|
||||
daselbst
|
||||
dass
|
||||
dasselbe
|
||||
davon
|
||||
davor
|
||||
dazu
|
||||
dazwischen
|
||||
daß
|
||||
dein
|
||||
deine
|
||||
deinem
|
||||
deinen
|
||||
deiner
|
||||
deines
|
||||
dem
|
||||
dementsprechend
|
||||
demgegenüber
|
||||
demgemäss
|
||||
demgemäß
|
||||
demselben
|
||||
demzufolge
|
||||
den
|
||||
denen
|
||||
denn
|
||||
denselben
|
||||
der
|
||||
deren
|
||||
derer
|
||||
derjenige
|
||||
derjenigen
|
||||
dermassen
|
||||
dermaßen
|
||||
derselbe
|
||||
derselben
|
||||
des
|
||||
deshalb
|
||||
desselben
|
||||
dessen
|
||||
deswegen
|
||||
dich
|
||||
die
|
||||
diejenige
|
||||
diejenigen
|
||||
dies
|
||||
diese
|
||||
dieselbe
|
||||
dieselben
|
||||
diesem
|
||||
diesen
|
||||
dieser
|
||||
dieses
|
||||
dir
|
||||
doch
|
||||
dort
|
||||
drei
|
||||
drin
|
||||
dritte
|
||||
dritten
|
||||
dritter
|
||||
drittes
|
||||
du
|
||||
durch
|
||||
durchaus
|
||||
durfte
|
||||
durften
|
||||
dürfen
|
||||
dürft
|
||||
e
|
||||
eben
|
||||
ebenso
|
||||
ehrlich
|
||||
ei
|
||||
ei,
|
||||
eigen
|
||||
eigene
|
||||
eigenen
|
||||
eigener
|
||||
eigenes
|
||||
ein
|
||||
einander
|
||||
eine
|
||||
einem
|
||||
einen
|
||||
einer
|
||||
eines
|
||||
einig
|
||||
einige
|
||||
einigem
|
||||
einigen
|
||||
einiger
|
||||
einiges
|
||||
einmal
|
||||
eins
|
||||
elf
|
||||
en
|
||||
ende
|
||||
endlich
|
||||
entweder
|
||||
er
|
||||
ernst
|
||||
erst
|
||||
erste
|
||||
ersten
|
||||
erster
|
||||
erstes
|
||||
es
|
||||
etwa
|
||||
etwas
|
||||
euch
|
||||
euer
|
||||
eure
|
||||
eurem
|
||||
euren
|
||||
eurer
|
||||
eures
|
||||
f
|
||||
folgende
|
||||
früher
|
||||
fünf
|
||||
fünfte
|
||||
fünften
|
||||
fünfter
|
||||
fünftes
|
||||
für
|
||||
g
|
||||
gab
|
||||
ganz
|
||||
ganze
|
||||
ganzen
|
||||
ganzer
|
||||
ganzes
|
||||
gar
|
||||
gedurft
|
||||
gegen
|
||||
gegenüber
|
||||
gehabt
|
||||
gehen
|
||||
geht
|
||||
gekannt
|
||||
gekonnt
|
||||
gemacht
|
||||
gemocht
|
||||
gemusst
|
||||
genug
|
||||
gerade
|
||||
gern
|
||||
gesagt
|
||||
geschweige
|
||||
gewesen
|
||||
gewollt
|
||||
geworden
|
||||
gibt
|
||||
ging
|
||||
gleich
|
||||
gott
|
||||
gross
|
||||
grosse
|
||||
grossen
|
||||
grosser
|
||||
grosses
|
||||
groß
|
||||
große
|
||||
großen
|
||||
großer
|
||||
großes
|
||||
gut
|
||||
gute
|
||||
guter
|
||||
gutes
|
||||
h
|
||||
hab
|
||||
habe
|
||||
haben
|
||||
habt
|
||||
hast
|
||||
hat
|
||||
hatte
|
||||
hatten
|
||||
hattest
|
||||
hattet
|
||||
heisst
|
||||
her
|
||||
heute
|
||||
hier
|
||||
hin
|
||||
hinter
|
||||
hoch
|
||||
hätte
|
||||
hätten
|
||||
i
|
||||
ich
|
||||
ihm
|
||||
ihn
|
||||
ihnen
|
||||
ihr
|
||||
ihre
|
||||
ihrem
|
||||
ihren
|
||||
ihrer
|
||||
ihres
|
||||
im
|
||||
immer
|
||||
in
|
||||
indem
|
||||
infolgedessen
|
||||
ins
|
||||
irgend
|
||||
ist
|
||||
j
|
||||
ja
|
||||
jahr
|
||||
jahre
|
||||
jahren
|
||||
je
|
||||
jede
|
||||
jedem
|
||||
jeden
|
||||
jeder
|
||||
jedermann
|
||||
jedermanns
|
||||
jedes
|
||||
jedoch
|
||||
jemand
|
||||
jemandem
|
||||
jemanden
|
||||
jene
|
||||
jenem
|
||||
jenen
|
||||
jener
|
||||
jenes
|
||||
jetzt
|
||||
k
|
||||
kam
|
||||
kann
|
||||
kannst
|
||||
kaum
|
||||
kein
|
||||
keine
|
||||
keinem
|
||||
keinen
|
||||
keiner
|
||||
keines
|
||||
kleine
|
||||
kleinen
|
||||
kleiner
|
||||
kleines
|
||||
kommen
|
||||
kommt
|
||||
konnte
|
||||
konnten
|
||||
kurz
|
||||
können
|
||||
könnt
|
||||
könnte
|
||||
l
|
||||
lang
|
||||
lange
|
||||
leicht
|
||||
leide
|
||||
lieber
|
||||
los
|
||||
m
|
||||
machen
|
||||
macht
|
||||
machte
|
||||
mag
|
||||
magst
|
||||
mahn
|
||||
mal
|
||||
man
|
||||
manche
|
||||
manchem
|
||||
manchen
|
||||
mancher
|
||||
manches
|
||||
mann
|
||||
mehr
|
||||
mein
|
||||
meine
|
||||
meinem
|
||||
meinen
|
||||
meiner
|
||||
meines
|
||||
mensch
|
||||
menschen
|
||||
mich
|
||||
mir
|
||||
mit
|
||||
mittel
|
||||
mochte
|
||||
mochten
|
||||
morgen
|
||||
muss
|
||||
musst
|
||||
musste
|
||||
mussten
|
||||
muß
|
||||
mußt
|
||||
möchte
|
||||
mögen
|
||||
möglich
|
||||
mögt
|
||||
müssen
|
||||
müsst
|
||||
müßt
|
||||
n
|
||||
na
|
||||
nach
|
||||
nachdem
|
||||
nahm
|
||||
natürlich
|
||||
neben
|
||||
nein
|
||||
neue
|
||||
neuen
|
||||
neun
|
||||
neunte
|
||||
neunten
|
||||
neunter
|
||||
neuntes
|
||||
nicht
|
||||
nichts
|
||||
nie
|
||||
niemand
|
||||
niemandem
|
||||
niemanden
|
||||
noch
|
||||
nun
|
||||
nur
|
||||
o
|
||||
ob
|
||||
oben
|
||||
oder
|
||||
offen
|
||||
oft
|
||||
ohne
|
||||
ordnung
|
||||
p
|
||||
q
|
||||
r
|
||||
recht
|
||||
rechte
|
||||
rechten
|
||||
rechter
|
||||
rechtes
|
||||
richtig
|
||||
rund
|
||||
s
|
||||
sa
|
||||
sache
|
||||
sagt
|
||||
sagte
|
||||
sah
|
||||
satt
|
||||
schlecht
|
||||
schluss
|
||||
schon
|
||||
sechs
|
||||
sechste
|
||||
sechsten
|
||||
sechster
|
||||
sechstes
|
||||
sehr
|
||||
sei
|
||||
seid
|
||||
seien
|
||||
sein
|
||||
seine
|
||||
seinem
|
||||
seinen
|
||||
seiner
|
||||
seines
|
||||
seit
|
||||
seitdem
|
||||
selbst
|
||||
sich
|
||||
sie
|
||||
sieben
|
||||
siebente
|
||||
siebenten
|
||||
siebenter
|
||||
siebentes
|
||||
sind
|
||||
so
|
||||
solang
|
||||
solche
|
||||
solchem
|
||||
solchen
|
||||
solcher
|
||||
solches
|
||||
soll
|
||||
sollen
|
||||
sollst
|
||||
sollt
|
||||
sollte
|
||||
sollten
|
||||
sondern
|
||||
sonst
|
||||
soweit
|
||||
sowie
|
||||
später
|
||||
startseite
|
||||
statt
|
||||
steht
|
||||
suche
|
||||
t
|
||||
tag
|
||||
tage
|
||||
tagen
|
||||
tat
|
||||
teil
|
||||
tel
|
||||
tritt
|
||||
trotzdem
|
||||
tun
|
||||
u
|
||||
uhr
|
||||
um
|
||||
und
|
||||
und?
|
||||
uns
|
||||
unse
|
||||
unsem
|
||||
unsen
|
||||
unser
|
||||
unsere
|
||||
unserer
|
||||
unses
|
||||
unter
|
||||
v
|
||||
vergangenen
|
||||
viel
|
||||
viele
|
||||
vielem
|
||||
vielen
|
||||
vielleicht
|
||||
vier
|
||||
vierte
|
||||
vierten
|
||||
vierter
|
||||
viertes
|
||||
vom
|
||||
von
|
||||
vor
|
||||
w
|
||||
wahr?
|
||||
wann
|
||||
war
|
||||
waren
|
||||
warst
|
||||
wart
|
||||
warum
|
||||
was
|
||||
weg
|
||||
wegen
|
||||
weil
|
||||
weit
|
||||
weiter
|
||||
weitere
|
||||
weiteren
|
||||
weiteres
|
||||
welche
|
||||
welchem
|
||||
welchen
|
||||
welcher
|
||||
welches
|
||||
wem
|
||||
wen
|
||||
wenig
|
||||
wenige
|
||||
weniger
|
||||
weniges
|
||||
wenigstens
|
||||
wenn
|
||||
wer
|
||||
werde
|
||||
werden
|
||||
werdet
|
||||
weshalb
|
||||
wessen
|
||||
wie
|
||||
wieder
|
||||
wieso
|
||||
will
|
||||
willst
|
||||
wir
|
||||
wird
|
||||
wirklich
|
||||
wirst
|
||||
wissen
|
||||
wo
|
||||
woher
|
||||
wohin
|
||||
wohl
|
||||
wollen
|
||||
wollt
|
||||
wollte
|
||||
wollten
|
||||
worden
|
||||
wurde
|
||||
wurden
|
||||
während
|
||||
währenddem
|
||||
währenddessen
|
||||
wäre
|
||||
würde
|
||||
würden
|
||||
x
|
||||
y
|
||||
z
|
||||
z.b
|
||||
zehn
|
||||
zehnte
|
||||
zehnten
|
||||
zehnter
|
||||
zehntes
|
||||
zeit
|
||||
zu
|
||||
zuerst
|
||||
zugleich
|
||||
zum
|
||||
zunächst
|
||||
zur
|
||||
zurück
|
||||
zusammen
|
||||
zwanzig
|
||||
zwar
|
||||
zwei
|
||||
zweite
|
||||
zweiten
|
||||
zweiter
|
||||
zweites
|
||||
zwischen
|
||||
zwölf
|
||||
über
|
||||
überhaupt
|
||||
übrigens
|
|
@ -0,0 +1,138 @@
|
|||
a
|
||||
about
|
||||
above
|
||||
after
|
||||
again
|
||||
against
|
||||
all
|
||||
an
|
||||
and
|
||||
any
|
||||
are
|
||||
aren
|
||||
as
|
||||
at
|
||||
be
|
||||
because
|
||||
been
|
||||
before
|
||||
being
|
||||
below
|
||||
between
|
||||
both
|
||||
but
|
||||
by
|
||||
can
|
||||
cannot
|
||||
could
|
||||
couldn
|
||||
did
|
||||
didn
|
||||
do
|
||||
does
|
||||
doesn
|
||||
doing
|
||||
don
|
||||
down
|
||||
during
|
||||
each
|
||||
few
|
||||
for
|
||||
from
|
||||
further
|
||||
had
|
||||
hadn
|
||||
has
|
||||
hasn
|
||||
have
|
||||
havent
|
||||
having
|
||||
he
|
||||
hed
|
||||
her
|
||||
here
|
||||
hers
|
||||
herself
|
||||
him
|
||||
himself
|
||||
his
|
||||
how
|
||||
if
|
||||
in
|
||||
into
|
||||
is
|
||||
isn
|
||||
it
|
||||
its
|
||||
itself
|
||||
let
|
||||
more
|
||||
most
|
||||
mustn
|
||||
myself
|
||||
no
|
||||
nor
|
||||
not
|
||||
of
|
||||
off
|
||||
on
|
||||
once
|
||||
only
|
||||
other
|
||||
ought
|
||||
our
|
||||
ours
|
||||
ourselves
|
||||
out
|
||||
over
|
||||
own
|
||||
s
|
||||
same
|
||||
shan
|
||||
she
|
||||
should
|
||||
shouldn
|
||||
so
|
||||
some
|
||||
such
|
||||
than
|
||||
that
|
||||
the
|
||||
their
|
||||
theirs
|
||||
themselves
|
||||
then
|
||||
there
|
||||
these
|
||||
they
|
||||
this
|
||||
those
|
||||
through
|
||||
to
|
||||
too
|
||||
under
|
||||
until
|
||||
up
|
||||
very
|
||||
was
|
||||
wasn
|
||||
we
|
||||
were
|
||||
weren
|
||||
what
|
||||
when
|
||||
where
|
||||
which
|
||||
while
|
||||
who
|
||||
whom
|
||||
why
|
||||
with
|
||||
won
|
||||
would
|
||||
wouldn
|
||||
you
|
||||
your
|
||||
yours
|
||||
yourself
|
||||
yourselves
|
|
@ -0,0 +1,720 @@
|
|||
a
|
||||
actualmente
|
||||
acuerdo
|
||||
adelante
|
||||
ademas
|
||||
además
|
||||
adrede
|
||||
afirmó
|
||||
agregó
|
||||
ahi
|
||||
ahora
|
||||
ahí
|
||||
al
|
||||
algo
|
||||
alguna
|
||||
algunas
|
||||
alguno
|
||||
algunos
|
||||
algún
|
||||
alli
|
||||
allí
|
||||
alrededor
|
||||
ambos
|
||||
ampleamos
|
||||
antano
|
||||
antaño
|
||||
ante
|
||||
anterior
|
||||
antes
|
||||
apenas
|
||||
aproximadamente
|
||||
aquel
|
||||
aquella
|
||||
aquellas
|
||||
aquello
|
||||
aquellos
|
||||
aqui
|
||||
aquél
|
||||
aquélla
|
||||
aquéllas
|
||||
aquéllos
|
||||
aquí
|
||||
arriba
|
||||
arribaabajo
|
||||
aseguró
|
||||
asi
|
||||
así
|
||||
atras
|
||||
aun
|
||||
aunque
|
||||
ayer
|
||||
añadió
|
||||
aún
|
||||
b
|
||||
bajo
|
||||
bastante
|
||||
bien
|
||||
breve
|
||||
buen
|
||||
buena
|
||||
buenas
|
||||
bueno
|
||||
buenos
|
||||
c
|
||||
cada
|
||||
casi
|
||||
cerca
|
||||
cierta
|
||||
ciertas
|
||||
cierto
|
||||
ciertos
|
||||
cinco
|
||||
claro
|
||||
comentó
|
||||
como
|
||||
con
|
||||
conmigo
|
||||
conocer
|
||||
conseguimos
|
||||
conseguir
|
||||
considera
|
||||
consideró
|
||||
consigo
|
||||
consigue
|
||||
consiguen
|
||||
consigues
|
||||
contigo
|
||||
contra
|
||||
cosas
|
||||
creo
|
||||
cual
|
||||
cuales
|
||||
cualquier
|
||||
cuando
|
||||
cuanta
|
||||
cuantas
|
||||
cuanto
|
||||
cuantos
|
||||
cuatro
|
||||
cuenta
|
||||
cuál
|
||||
cuáles
|
||||
cuándo
|
||||
cuánta
|
||||
cuántas
|
||||
cuánto
|
||||
cuántos
|
||||
cómo
|
||||
d
|
||||
da
|
||||
dado
|
||||
dan
|
||||
dar
|
||||
de
|
||||
debajo
|
||||
debe
|
||||
deben
|
||||
debido
|
||||
decir
|
||||
dejó
|
||||
del
|
||||
delante
|
||||
demasiado
|
||||
demás
|
||||
dentro
|
||||
deprisa
|
||||
desde
|
||||
despacio
|
||||
despues
|
||||
después
|
||||
detras
|
||||
detrás
|
||||
dia
|
||||
dias
|
||||
dice
|
||||
dicen
|
||||
dicho
|
||||
dieron
|
||||
diferente
|
||||
diferentes
|
||||
dijeron
|
||||
dijo
|
||||
dio
|
||||
donde
|
||||
dos
|
||||
durante
|
||||
día
|
||||
días
|
||||
dónde
|
||||
e
|
||||
ejemplo
|
||||
el
|
||||
ella
|
||||
ellas
|
||||
ello
|
||||
ellos
|
||||
embargo
|
||||
empleais
|
||||
emplean
|
||||
emplear
|
||||
empleas
|
||||
empleo
|
||||
en
|
||||
encima
|
||||
encuentra
|
||||
enfrente
|
||||
enseguida
|
||||
entonces
|
||||
entre
|
||||
era
|
||||
erais
|
||||
eramos
|
||||
eran
|
||||
eras
|
||||
eres
|
||||
es
|
||||
esa
|
||||
esas
|
||||
ese
|
||||
eso
|
||||
esos
|
||||
esta
|
||||
estaba
|
||||
estabais
|
||||
estaban
|
||||
estabas
|
||||
estad
|
||||
estada
|
||||
estadas
|
||||
estado
|
||||
estados
|
||||
estais
|
||||
estamos
|
||||
estan
|
||||
estando
|
||||
estar
|
||||
estaremos
|
||||
estará
|
||||
estarán
|
||||
estarás
|
||||
estaré
|
||||
estaréis
|
||||
estaría
|
||||
estaríais
|
||||
estaríamos
|
||||
estarían
|
||||
estarías
|
||||
estas
|
||||
este
|
||||
estemos
|
||||
esto
|
||||
estos
|
||||
estoy
|
||||
estuve
|
||||
estuviera
|
||||
estuvierais
|
||||
estuvieran
|
||||
estuvieras
|
||||
estuvieron
|
||||
estuviese
|
||||
estuvieseis
|
||||
estuviesen
|
||||
estuvieses
|
||||
estuvimos
|
||||
estuviste
|
||||
estuvisteis
|
||||
estuviéramos
|
||||
estuviésemos
|
||||
estuvo
|
||||
está
|
||||
estábamos
|
||||
estáis
|
||||
están
|
||||
estás
|
||||
esté
|
||||
estéis
|
||||
estén
|
||||
estés
|
||||
ex
|
||||
excepto
|
||||
existe
|
||||
existen
|
||||
explicó
|
||||
expresó
|
||||
f
|
||||
fin
|
||||
final
|
||||
fue
|
||||
fuera
|
||||
fuerais
|
||||
fueran
|
||||
fueras
|
||||
fueron
|
||||
fuese
|
||||
fueseis
|
||||
fuesen
|
||||
fueses
|
||||
fui
|
||||
fuimos
|
||||
fuiste
|
||||
fuisteis
|
||||
fuéramos
|
||||
fuésemos
|
||||
g
|
||||
general
|
||||
gran
|
||||
grandes
|
||||
gueno
|
||||
h
|
||||
ha
|
||||
haber
|
||||
habia
|
||||
habida
|
||||
habidas
|
||||
habido
|
||||
habidos
|
||||
habiendo
|
||||
habla
|
||||
hablan
|
||||
habremos
|
||||
habrá
|
||||
habrán
|
||||
habrás
|
||||
habré
|
||||
habréis
|
||||
habría
|
||||
habríais
|
||||
habríamos
|
||||
habrían
|
||||
habrías
|
||||
habéis
|
||||
había
|
||||
habíais
|
||||
habíamos
|
||||
habían
|
||||
habías
|
||||
hace
|
||||
haceis
|
||||
hacemos
|
||||
hacen
|
||||
hacer
|
||||
hacerlo
|
||||
haces
|
||||
hacia
|
||||
haciendo
|
||||
hago
|
||||
han
|
||||
has
|
||||
hasta
|
||||
hay
|
||||
haya
|
||||
hayamos
|
||||
hayan
|
||||
hayas
|
||||
hayáis
|
||||
he
|
||||
hecho
|
||||
hemos
|
||||
hicieron
|
||||
hizo
|
||||
horas
|
||||
hoy
|
||||
hube
|
||||
hubiera
|
||||
hubierais
|
||||
hubieran
|
||||
hubieras
|
||||
hubieron
|
||||
hubiese
|
||||
hubieseis
|
||||
hubiesen
|
||||
hubieses
|
||||
hubimos
|
||||
hubiste
|
||||
hubisteis
|
||||
hubiéramos
|
||||
hubiésemos
|
||||
hubo
|
||||
i
|
||||
igual
|
||||
incluso
|
||||
indicó
|
||||
informo
|
||||
informó
|
||||
intenta
|
||||
intentais
|
||||
intentamos
|
||||
intentan
|
||||
intentar
|
||||
intentas
|
||||
intento
|
||||
ir
|
||||
j
|
||||
junto
|
||||
k
|
||||
l
|
||||
la
|
||||
lado
|
||||
largo
|
||||
las
|
||||
le
|
||||
lejos
|
||||
les
|
||||
llegó
|
||||
lleva
|
||||
llevar
|
||||
lo
|
||||
los
|
||||
luego
|
||||
lugar
|
||||
m
|
||||
mal
|
||||
manera
|
||||
manifestó
|
||||
mas
|
||||
mayor
|
||||
me
|
||||
mediante
|
||||
medio
|
||||
mejor
|
||||
mencionó
|
||||
menos
|
||||
menudo
|
||||
mi
|
||||
mia
|
||||
mias
|
||||
mientras
|
||||
mio
|
||||
mios
|
||||
mis
|
||||
misma
|
||||
mismas
|
||||
mismo
|
||||
mismos
|
||||
modo
|
||||
momento
|
||||
mucha
|
||||
muchas
|
||||
mucho
|
||||
muchos
|
||||
muy
|
||||
más
|
||||
mí
|
||||
mía
|
||||
mías
|
||||
mío
|
||||
míos
|
||||
n
|
||||
nada
|
||||
nadie
|
||||
ni
|
||||
ninguna
|
||||
ningunas
|
||||
ninguno
|
||||
ningunos
|
||||
ningún
|
||||
no
|
||||
nos
|
||||
nosotras
|
||||
nosotros
|
||||
nuestra
|
||||
nuestras
|
||||
nuestro
|
||||
nuestros
|
||||
nueva
|
||||
nuevas
|
||||
nuevo
|
||||
nuevos
|
||||
nunca
|
||||
o
|
||||
ocho
|
||||
os
|
||||
otra
|
||||
otras
|
||||
otro
|
||||
otros
|
||||
p
|
||||
pais
|
||||
para
|
||||
parece
|
||||
parte
|
||||
partir
|
||||
pasada
|
||||
pasado
|
||||
paìs
|
||||
peor
|
||||
pero
|
||||
pesar
|
||||
poca
|
||||
pocas
|
||||
poco
|
||||
pocos
|
||||
podeis
|
||||
podemos
|
||||
poder
|
||||
podria
|
||||
podriais
|
||||
podriamos
|
||||
podrian
|
||||
podrias
|
||||
podrá
|
||||
podrán
|
||||
podría
|
||||
podrían
|
||||
poner
|
||||
por
|
||||
por qué
|
||||
porque
|
||||
posible
|
||||
primer
|
||||
primera
|
||||
primero
|
||||
primeros
|
||||
principalmente
|
||||
pronto
|
||||
propia
|
||||
propias
|
||||
propio
|
||||
propios
|
||||
proximo
|
||||
próximo
|
||||
próximos
|
||||
pudo
|
||||
pueda
|
||||
puede
|
||||
pueden
|
||||
puedo
|
||||
pues
|
||||
q
|
||||
qeu
|
||||
que
|
||||
quedó
|
||||
queremos
|
||||
quien
|
||||
quienes
|
||||
quiere
|
||||
quiza
|
||||
quizas
|
||||
quizá
|
||||
quizás
|
||||
quién
|
||||
quiénes
|
||||
qué
|
||||
r
|
||||
raras
|
||||
realizado
|
||||
realizar
|
||||
realizó
|
||||
repente
|
||||
respecto
|
||||
s
|
||||
sabe
|
||||
sabeis
|
||||
sabemos
|
||||
saben
|
||||
saber
|
||||
sabes
|
||||
sal
|
||||
salvo
|
||||
se
|
||||
sea
|
||||
seamos
|
||||
sean
|
||||
seas
|
||||
segun
|
||||
segunda
|
||||
segundo
|
||||
según
|
||||
seis
|
||||
ser
|
||||
sera
|
||||
seremos
|
||||
será
|
||||
serán
|
||||
serás
|
||||
seré
|
||||
seréis
|
||||
sería
|
||||
seríais
|
||||
seríamos
|
||||
serían
|
||||
serías
|
||||
seáis
|
||||
señaló
|
||||
si
|
||||
sido
|
||||
siempre
|
||||
siendo
|
||||
siete
|
||||
sigue
|
||||
siguiente
|
||||
sin
|
||||
sino
|
||||
sobre
|
||||
sois
|
||||
sola
|
||||
solamente
|
||||
solas
|
||||
solo
|
||||
solos
|
||||
somos
|
||||
son
|
||||
soy
|
||||
soyos
|
||||
su
|
||||
supuesto
|
||||
sus
|
||||
suya
|
||||
suyas
|
||||
suyo
|
||||
suyos
|
||||
sé
|
||||
sí
|
||||
sólo
|
||||
t
|
||||
tal
|
||||
tambien
|
||||
también
|
||||
tampoco
|
||||
tan
|
||||
tanto
|
||||
tarde
|
||||
te
|
||||
temprano
|
||||
tendremos
|
||||
tendrá
|
||||
tendrán
|
||||
tendrás
|
||||
tendré
|
||||
tendréis
|
||||
tendría
|
||||
tendríais
|
||||
tendríamos
|
||||
tendrían
|
||||
tendrías
|
||||
tened
|
||||
teneis
|
||||
tenemos
|
||||
tener
|
||||
tenga
|
||||
tengamos
|
||||
tengan
|
||||
tengas
|
||||
tengo
|
||||
tengáis
|
||||
tenida
|
||||
tenidas
|
||||
tenido
|
||||
tenidos
|
||||
teniendo
|
||||
tenéis
|
||||
tenía
|
||||
teníais
|
||||
teníamos
|
||||
tenían
|
||||
tenías
|
||||
tercera
|
||||
ti
|
||||
tiempo
|
||||
tiene
|
||||
tienen
|
||||
tienes
|
||||
toda
|
||||
todas
|
||||
todavia
|
||||
todavía
|
||||
todo
|
||||
todos
|
||||
trabaja
|
||||
trabajais
|
||||
trabajamos
|
||||
trabajan
|
||||
trabajar
|
||||
trabajas
|
||||
trabajo
|
||||
tras
|
||||
trata
|
||||
través
|
||||
tres
|
||||
tu
|
||||
tus
|
||||
tuve
|
||||
tuviera
|
||||
tuvierais
|
||||
tuvieran
|
||||
tuvieras
|
||||
tuvieron
|
||||
tuviese
|
||||
tuvieseis
|
||||
tuviesen
|
||||
tuvieses
|
||||
tuvimos
|
||||
tuviste
|
||||
tuvisteis
|
||||
tuviéramos
|
||||
tuviésemos
|
||||
tuvo
|
||||
tuya
|
||||
tuyas
|
||||
tuyo
|
||||
tuyos
|
||||
tú
|
||||
u
|
||||
ultimo
|
||||
un
|
||||
una
|
||||
unas
|
||||
uno
|
||||
unos
|
||||
usa
|
||||
usais
|
||||
usamos
|
||||
usan
|
||||
usar
|
||||
usas
|
||||
uso
|
||||
usted
|
||||
ustedes
|
||||
v
|
||||
va
|
||||
vais
|
||||
valor
|
||||
vamos
|
||||
van
|
||||
varias
|
||||
varios
|
||||
vaya
|
||||
veces
|
||||
ver
|
||||
verdad
|
||||
verdadera
|
||||
verdadero
|
||||
vez
|
||||
vosotras
|
||||
vosotros
|
||||
voy
|
||||
vuestra
|
||||
vuestras
|
||||
vuestro
|
||||
vuestros
|
||||
w
|
||||
x
|
||||
y
|
||||
ya
|
||||
yo
|
||||
z
|
||||
él
|
||||
éramos
|
||||
ésa
|
||||
ésas
|
||||
ése
|
||||
ésos
|
||||
ésta
|
||||
éstas
|
||||
éste
|
||||
éstos
|
||||
última
|
||||
últimas
|
||||
último
|
||||
últimos
|
|
@ -0,0 +1,688 @@
|
|||
a
|
||||
abord
|
||||
absolument
|
||||
afin
|
||||
ah
|
||||
ai
|
||||
aie
|
||||
aient
|
||||
aies
|
||||
ailleurs
|
||||
ainsi
|
||||
ait
|
||||
allaient
|
||||
allo
|
||||
allons
|
||||
allô
|
||||
alors
|
||||
anterieur
|
||||
anterieure
|
||||
anterieures
|
||||
apres
|
||||
après
|
||||
as
|
||||
assez
|
||||
attendu
|
||||
au
|
||||
aucun
|
||||
aucune
|
||||
aucuns
|
||||
aujourd
|
||||
aujourd'hui
|
||||
aupres
|
||||
auquel
|
||||
aura
|
||||
aurai
|
||||
auraient
|
||||
aurais
|
||||
aurait
|
||||
auras
|
||||
aurez
|
||||
auriez
|
||||
aurions
|
||||
aurons
|
||||
auront
|
||||
aussi
|
||||
autre
|
||||
autrefois
|
||||
autrement
|
||||
autres
|
||||
autrui
|
||||
aux
|
||||
auxquelles
|
||||
auxquels
|
||||
avaient
|
||||
avais
|
||||
avait
|
||||
avant
|
||||
avec
|
||||
avez
|
||||
aviez
|
||||
avions
|
||||
avoir
|
||||
avons
|
||||
ayant
|
||||
ayez
|
||||
ayons
|
||||
b
|
||||
bah
|
||||
bas
|
||||
basee
|
||||
bat
|
||||
beau
|
||||
beaucoup
|
||||
bien
|
||||
bigre
|
||||
bon
|
||||
boum
|
||||
bravo
|
||||
brrr
|
||||
c
|
||||
car
|
||||
ce
|
||||
ceci
|
||||
cela
|
||||
celle
|
||||
celle-ci
|
||||
celle-là
|
||||
celles
|
||||
celles-ci
|
||||
celles-là
|
||||
celui
|
||||
celui-ci
|
||||
celui-là
|
||||
celà
|
||||
cent
|
||||
cependant
|
||||
certain
|
||||
certaine
|
||||
certaines
|
||||
certains
|
||||
certes
|
||||
ces
|
||||
cet
|
||||
cette
|
||||
ceux
|
||||
ceux-ci
|
||||
ceux-là
|
||||
chacun
|
||||
chacune
|
||||
chaque
|
||||
cher
|
||||
chers
|
||||
chez
|
||||
chiche
|
||||
chut
|
||||
chère
|
||||
chères
|
||||
ci
|
||||
cinq
|
||||
cinquantaine
|
||||
cinquante
|
||||
cinquantième
|
||||
cinquième
|
||||
clac
|
||||
clic
|
||||
combien
|
||||
comme
|
||||
comment
|
||||
comparable
|
||||
comparables
|
||||
compris
|
||||
concernant
|
||||
contre
|
||||
couic
|
||||
crac
|
||||
d
|
||||
da
|
||||
dans
|
||||
de
|
||||
debout
|
||||
dedans
|
||||
dehors
|
||||
deja
|
||||
delà
|
||||
depuis
|
||||
dernier
|
||||
derniere
|
||||
derriere
|
||||
derrière
|
||||
des
|
||||
desormais
|
||||
desquelles
|
||||
desquels
|
||||
dessous
|
||||
dessus
|
||||
deux
|
||||
deuxième
|
||||
deuxièmement
|
||||
devant
|
||||
devers
|
||||
devra
|
||||
devrait
|
||||
different
|
||||
differentes
|
||||
differents
|
||||
différent
|
||||
différente
|
||||
différentes
|
||||
différents
|
||||
dire
|
||||
directe
|
||||
directement
|
||||
dit
|
||||
dite
|
||||
dits
|
||||
divers
|
||||
diverse
|
||||
diverses
|
||||
dix
|
||||
dix-huit
|
||||
dix-neuf
|
||||
dix-sept
|
||||
dixième
|
||||
doit
|
||||
doivent
|
||||
donc
|
||||
dont
|
||||
dos
|
||||
douze
|
||||
douzième
|
||||
dring
|
||||
droite
|
||||
du
|
||||
duquel
|
||||
durant
|
||||
dès
|
||||
début
|
||||
désormais
|
||||
e
|
||||
effet
|
||||
egale
|
||||
egalement
|
||||
egales
|
||||
eh
|
||||
elle
|
||||
elle-même
|
||||
elles
|
||||
elles-mêmes
|
||||
en
|
||||
encore
|
||||
enfin
|
||||
entre
|
||||
envers
|
||||
es
|
||||
essai
|
||||
est
|
||||
et
|
||||
etant
|
||||
etc
|
||||
etre
|
||||
eu
|
||||
eue
|
||||
eues
|
||||
euh
|
||||
eurent
|
||||
eus
|
||||
eusse
|
||||
eussent
|
||||
eusses
|
||||
eussiez
|
||||
eussions
|
||||
eut
|
||||
eux
|
||||
eux-mêmes
|
||||
exactement
|
||||
excepté
|
||||
extenso
|
||||
exterieur
|
||||
eûmes
|
||||
eût
|
||||
eûtes
|
||||
f
|
||||
fais
|
||||
faisaient
|
||||
faisant
|
||||
fait
|
||||
faites
|
||||
façon
|
||||
feront
|
||||
fi
|
||||
flac
|
||||
floc
|
||||
fois
|
||||
font
|
||||
force
|
||||
furent
|
||||
fus
|
||||
fusse
|
||||
fussent
|
||||
fusses
|
||||
fussiez
|
||||
fussions
|
||||
fut
|
||||
fûmes
|
||||
fût
|
||||
fûtes
|
||||
g
|
||||
gens
|
||||
h
|
||||
ha
|
||||
haut
|
||||
hein
|
||||
hem
|
||||
hep
|
||||
hi
|
||||
ho
|
||||
holà
|
||||
hop
|
||||
hormis
|
||||
hors
|
||||
hou
|
||||
houp
|
||||
hue
|
||||
hui
|
||||
huit
|
||||
huitième
|
||||
hum
|
||||
hurrah
|
||||
hé
|
||||
hélas
|
||||
i
|
||||
ici
|
||||
il
|
||||
ils
|
||||
importe
|
||||
j
|
||||
je
|
||||
jusqu
|
||||
jusque
|
||||
juste
|
||||
k
|
||||
l
|
||||
la
|
||||
laisser
|
||||
laquelle
|
||||
las
|
||||
le
|
||||
lequel
|
||||
les
|
||||
lesquelles
|
||||
lesquels
|
||||
leur
|
||||
leurs
|
||||
longtemps
|
||||
lors
|
||||
lorsque
|
||||
lui
|
||||
lui-meme
|
||||
lui-même
|
||||
là
|
||||
lès
|
||||
m
|
||||
ma
|
||||
maint
|
||||
maintenant
|
||||
mais
|
||||
malgre
|
||||
malgré
|
||||
maximale
|
||||
me
|
||||
meme
|
||||
memes
|
||||
merci
|
||||
mes
|
||||
mien
|
||||
mienne
|
||||
miennes
|
||||
miens
|
||||
mille
|
||||
mince
|
||||
mine
|
||||
minimale
|
||||
moi
|
||||
moi-meme
|
||||
moi-même
|
||||
moindres
|
||||
moins
|
||||
mon
|
||||
mot
|
||||
moyennant
|
||||
multiple
|
||||
multiples
|
||||
même
|
||||
mêmes
|
||||
n
|
||||
na
|
||||
naturel
|
||||
naturelle
|
||||
naturelles
|
||||
ne
|
||||
neanmoins
|
||||
necessaire
|
||||
necessairement
|
||||
neuf
|
||||
neuvième
|
||||
ni
|
||||
nombreuses
|
||||
nombreux
|
||||
nommés
|
||||
non
|
||||
nos
|
||||
notamment
|
||||
notre
|
||||
nous
|
||||
nous-mêmes
|
||||
nouveau
|
||||
nouveaux
|
||||
nul
|
||||
néanmoins
|
||||
nôtre
|
||||
nôtres
|
||||
o
|
||||
oh
|
||||
ohé
|
||||
ollé
|
||||
olé
|
||||
on
|
||||
ont
|
||||
onze
|
||||
onzième
|
||||
ore
|
||||
ou
|
||||
ouf
|
||||
ouias
|
||||
oust
|
||||
ouste
|
||||
outre
|
||||
ouvert
|
||||
ouverte
|
||||
ouverts
|
||||
o|
|
||||
où
|
||||
p
|
||||
paf
|
||||
pan
|
||||
par
|
||||
parce
|
||||
parfois
|
||||
parle
|
||||
parlent
|
||||
parler
|
||||
parmi
|
||||
parole
|
||||
parseme
|
||||
partant
|
||||
particulier
|
||||
particulière
|
||||
particulièrement
|
||||
pas
|
||||
passé
|
||||
pendant
|
||||
pense
|
||||
permet
|
||||
personne
|
||||
personnes
|
||||
peu
|
||||
peut
|
||||
peuvent
|
||||
peux
|
||||
pff
|
||||
pfft
|
||||
pfut
|
||||
pif
|
||||
pire
|
||||
pièce
|
||||
plein
|
||||
plouf
|
||||
plupart
|
||||
plus
|
||||
plusieurs
|
||||
plutôt
|
||||
possessif
|
||||
possessifs
|
||||
possible
|
||||
possibles
|
||||
pouah
|
||||
pour
|
||||
pourquoi
|
||||
pourrais
|
||||
pourrait
|
||||
pouvait
|
||||
prealable
|
||||
precisement
|
||||
premier
|
||||
première
|
||||
premièrement
|
||||
pres
|
||||
probable
|
||||
probante
|
||||
procedant
|
||||
proche
|
||||
près
|
||||
psitt
|
||||
pu
|
||||
puis
|
||||
puisque
|
||||
pur
|
||||
pure
|
||||
q
|
||||
qu
|
||||
quand
|
||||
quant
|
||||
quant-à-soi
|
||||
quanta
|
||||
quarante
|
||||
quatorze
|
||||
quatre
|
||||
quatre-vingt
|
||||
quatrième
|
||||
quatrièmement
|
||||
que
|
||||
quel
|
||||
quelconque
|
||||
quelle
|
||||
quelles
|
||||
quelqu'un
|
||||
quelque
|
||||
quelques
|
||||
quels
|
||||
qui
|
||||
quiconque
|
||||
quinze
|
||||
quoi
|
||||
quoique
|
||||
r
|
||||
rare
|
||||
rarement
|
||||
rares
|
||||
relative
|
||||
relativement
|
||||
remarquable
|
||||
rend
|
||||
rendre
|
||||
restant
|
||||
reste
|
||||
restent
|
||||
restrictif
|
||||
retour
|
||||
revoici
|
||||
revoilà
|
||||
rien
|
||||
s
|
||||
sa
|
||||
sacrebleu
|
||||
sait
|
||||
sans
|
||||
sapristi
|
||||
sauf
|
||||
se
|
||||
sein
|
||||
seize
|
||||
selon
|
||||
semblable
|
||||
semblaient
|
||||
semble
|
||||
semblent
|
||||
sent
|
||||
sept
|
||||
septième
|
||||
sera
|
||||
serai
|
||||
seraient
|
||||
serais
|
||||
serait
|
||||
seras
|
||||
serez
|
||||
seriez
|
||||
serions
|
||||
serons
|
||||
seront
|
||||
ses
|
||||
seul
|
||||
seule
|
||||
seulement
|
||||
si
|
||||
sien
|
||||
sienne
|
||||
siennes
|
||||
siens
|
||||
sinon
|
||||
six
|
||||
sixième
|
||||
soi
|
||||
soi-même
|
||||
soient
|
||||
sois
|
||||
soit
|
||||
soixante
|
||||
sommes
|
||||
son
|
||||
sont
|
||||
sous
|
||||
souvent
|
||||
soyez
|
||||
soyons
|
||||
specifique
|
||||
specifiques
|
||||
speculatif
|
||||
stop
|
||||
strictement
|
||||
subtiles
|
||||
suffisant
|
||||
suffisante
|
||||
suffit
|
||||
suis
|
||||
suit
|
||||
suivant
|
||||
suivante
|
||||
suivantes
|
||||
suivants
|
||||
suivre
|
||||
sujet
|
||||
superpose
|
||||
sur
|
||||
surtout
|
||||
t
|
||||
ta
|
||||
tac
|
||||
tandis
|
||||
tant
|
||||
tardive
|
||||
te
|
||||
tel
|
||||
telle
|
||||
tellement
|
||||
telles
|
||||
tels
|
||||
tenant
|
||||
tend
|
||||
tenir
|
||||
tente
|
||||
tes
|
||||
tic
|
||||
tien
|
||||
tienne
|
||||
tiennes
|
||||
tiens
|
||||
toc
|
||||
toi
|
||||
toi-même
|
||||
ton
|
||||
touchant
|
||||
toujours
|
||||
tous
|
||||
tout
|
||||
toute
|
||||
toutefois
|
||||
toutes
|
||||
treize
|
||||
trente
|
||||
tres
|
||||
trois
|
||||
troisième
|
||||
troisièmement
|
||||
trop
|
||||
très
|
||||
tsoin
|
||||
tsouin
|
||||
tu
|
||||
té
|
||||
u
|
||||
un
|
||||
une
|
||||
unes
|
||||
uniformement
|
||||
unique
|
||||
uniques
|
||||
uns
|
||||
v
|
||||
va
|
||||
vais
|
||||
valeur
|
||||
vas
|
||||
vers
|
||||
via
|
||||
vif
|
||||
vifs
|
||||
vingt
|
||||
vivat
|
||||
vive
|
||||
vives
|
||||
vlan
|
||||
voici
|
||||
voie
|
||||
voient
|
||||
voilà
|
||||
vont
|
||||
vos
|
||||
votre
|
||||
vous
|
||||
vous-mêmes
|
||||
vu
|
||||
vé
|
||||
vôtre
|
||||
vôtres
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
zut
|
||||
à
|
||||
â
|
||||
ça
|
||||
ès
|
||||
étaient
|
||||
étais
|
||||
était
|
||||
étant
|
||||
état
|
||||
étiez
|
||||
étions
|
||||
été
|
||||
étée
|
||||
étées
|
||||
étés
|
||||
êtes
|
||||
être
|
||||
ô
|
|
@ -0,0 +1,847 @@
|
|||
ένα
|
||||
έναν
|
||||
ένας
|
||||
αι
|
||||
ακομα
|
||||
ακομη
|
||||
ακριβως
|
||||
αληθεια
|
||||
αληθινα
|
||||
αλλα
|
||||
αλλαχου
|
||||
αλλες
|
||||
αλλη
|
||||
αλλην
|
||||
αλλης
|
||||
αλλιως
|
||||
αλλιωτικα
|
||||
αλλο
|
||||
αλλοι
|
||||
αλλοιως
|
||||
αλλοιωτικα
|
||||
αλλον
|
||||
αλλος
|
||||
αλλοτε
|
||||
αλλου
|
||||
αλλους
|
||||
αλλων
|
||||
αμα
|
||||
αμεσα
|
||||
αμεσως
|
||||
αν
|
||||
ανα
|
||||
αναμεσα
|
||||
αναμεταξυ
|
||||
ανευ
|
||||
αντι
|
||||
αντιπερα
|
||||
αντις
|
||||
ανω
|
||||
ανωτερω
|
||||
αξαφνα
|
||||
απ
|
||||
απεναντι
|
||||
απο
|
||||
αποψε
|
||||
από
|
||||
αρα
|
||||
αραγε
|
||||
αργα
|
||||
αργοτερο
|
||||
αριστερα
|
||||
αρκετα
|
||||
αρχικα
|
||||
ας
|
||||
αυριο
|
||||
αυτα
|
||||
αυτες
|
||||
αυτεσ
|
||||
αυτη
|
||||
αυτην
|
||||
αυτης
|
||||
αυτο
|
||||
αυτοι
|
||||
αυτον
|
||||
αυτος
|
||||
αυτοσ
|
||||
αυτου
|
||||
αυτους
|
||||
αυτουσ
|
||||
αυτων
|
||||
αφοτου
|
||||
αφου
|
||||
αἱ
|
||||
αἳ
|
||||
αἵ
|
||||
αὐτόσ
|
||||
αὐτὸς
|
||||
αὖ
|
||||
α∆ιακοπα
|
||||
βεβαια
|
||||
βεβαιοτατα
|
||||
γάρ
|
||||
γα
|
||||
γα^
|
||||
γε
|
||||
γι
|
||||
για
|
||||
γοῦν
|
||||
γρηγορα
|
||||
γυρω
|
||||
γὰρ
|
||||
δ'
|
||||
δέ
|
||||
δή
|
||||
δαί
|
||||
δαίσ
|
||||
δαὶ
|
||||
δαὶς
|
||||
δε
|
||||
δεν
|
||||
δι
|
||||
δι'
|
||||
διά
|
||||
δια
|
||||
διὰ
|
||||
δὲ
|
||||
δὴ
|
||||
δ’
|
||||
εαν
|
||||
εαυτο
|
||||
εαυτον
|
||||
εαυτου
|
||||
εαυτους
|
||||
εαυτων
|
||||
εγκαιρα
|
||||
εγκαιρως
|
||||
εγω
|
||||
ειθε
|
||||
ειμαι
|
||||
ειμαστε
|
||||
ειναι
|
||||
εις
|
||||
εισαι
|
||||
εισαστε
|
||||
ειστε
|
||||
ειτε
|
||||
ειχα
|
||||
ειχαμε
|
||||
ειχαν
|
||||
ειχατε
|
||||
ειχε
|
||||
ειχες
|
||||
ει∆εμη
|
||||
εκ
|
||||
εκαστα
|
||||
εκαστες
|
||||
εκαστη
|
||||
εκαστην
|
||||
εκαστης
|
||||
εκαστο
|
||||
εκαστοι
|
||||
εκαστον
|
||||
εκαστος
|
||||
εκαστου
|
||||
εκαστους
|
||||
εκαστων
|
||||
εκει
|
||||
εκεινα
|
||||
εκεινες
|
||||
εκεινεσ
|
||||
εκεινη
|
||||
εκεινην
|
||||
εκεινης
|
||||
εκεινο
|
||||
εκεινοι
|
||||
εκεινον
|
||||
εκεινος
|
||||
εκεινοσ
|
||||
εκεινου
|
||||
εκεινους
|
||||
εκεινουσ
|
||||
εκεινων
|
||||
εκτος
|
||||
εμας
|
||||
εμεις
|
||||
εμενα
|
||||
εμπρος
|
||||
εν
|
||||
ενα
|
||||
εναν
|
||||
ενας
|
||||
ενος
|
||||
εντελως
|
||||
εντος
|
||||
εντωμεταξυ
|
||||
ενω
|
||||
ενός
|
||||
εξ
|
||||
εξαφνα
|
||||
εξης
|
||||
εξισου
|
||||
εξω
|
||||
επ
|
||||
επί
|
||||
επανω
|
||||
επειτα
|
||||
επει∆η
|
||||
επι
|
||||
επισης
|
||||
επομενως
|
||||
εσας
|
||||
εσεις
|
||||
εσενα
|
||||
εστω
|
||||
εσυ
|
||||
ετερα
|
||||
ετεραι
|
||||
ετερας
|
||||
ετερες
|
||||
ετερη
|
||||
ετερης
|
||||
ετερο
|
||||
ετεροι
|
||||
ετερον
|
||||
ετερος
|
||||
ετερου
|
||||
ετερους
|
||||
ετερων
|
||||
ετουτα
|
||||
ετουτες
|
||||
ετουτη
|
||||
ετουτην
|
||||
ετουτης
|
||||
ετουτο
|
||||
ετουτοι
|
||||
ετουτον
|
||||
ετουτος
|
||||
ετουτου
|
||||
ετουτους
|
||||
ετουτων
|
||||
ετσι
|
||||
ευγε
|
||||
ευθυς
|
||||
ευτυχως
|
||||
εφεξης
|
||||
εχει
|
||||
εχεις
|
||||
εχετε
|
||||
εχθες
|
||||
εχομε
|
||||
εχουμε
|
||||
εχουν
|
||||
εχτες
|
||||
εχω
|
||||
εως
|
||||
εἰ
|
||||
εἰμί
|
||||
εἰμὶ
|
||||
εἰς
|
||||
εἰσ
|
||||
εἴ
|
||||
εἴμι
|
||||
εἴτε
|
||||
ε∆ω
|
||||
η
|
||||
ημασταν
|
||||
ημαστε
|
||||
ημουν
|
||||
ησασταν
|
||||
ησαστε
|
||||
ησουν
|
||||
ηταν
|
||||
ητανε
|
||||
ητοι
|
||||
ηττον
|
||||
η∆η
|
||||
θα
|
||||
ι
|
||||
ιι
|
||||
ιιι
|
||||
ισαμε
|
||||
ισια
|
||||
ισως
|
||||
ισωσ
|
||||
ι∆ια
|
||||
ι∆ιαν
|
||||
ι∆ιας
|
||||
ι∆ιες
|
||||
ι∆ιο
|
||||
ι∆ιοι
|
||||
ι∆ιον
|
||||
ι∆ιος
|
||||
ι∆ιου
|
||||
ι∆ιους
|
||||
ι∆ιων
|
||||
ι∆ιως
|
||||
κ
|
||||
καί
|
||||
καίτοι
|
||||
καθ
|
||||
καθε
|
||||
καθεμια
|
||||
καθεμιας
|
||||
καθενα
|
||||
καθενας
|
||||
καθενος
|
||||
καθετι
|
||||
καθολου
|
||||
καθως
|
||||
και
|
||||
κακα
|
||||
κακως
|
||||
καλα
|
||||
καλως
|
||||
καμια
|
||||
καμιαν
|
||||
καμιας
|
||||
καμποσα
|
||||
καμποσες
|
||||
καμποση
|
||||
καμποσην
|
||||
καμποσης
|
||||
καμποσο
|
||||
καμποσοι
|
||||
καμποσον
|
||||
καμποσος
|
||||
καμποσου
|
||||
καμποσους
|
||||
καμποσων
|
||||
κανεις
|
||||
κανεν
|
||||
κανενα
|
||||
κανεναν
|
||||
κανενας
|
||||
κανενος
|
||||
καποια
|
||||
καποιαν
|
||||
καποιας
|
||||
καποιες
|
||||
καποιο
|
||||
καποιοι
|
||||
καποιον
|
||||
καποιος
|
||||
καποιου
|
||||
καποιους
|
||||
καποιων
|
||||
καποτε
|
||||
καπου
|
||||
καπως
|
||||
κατ
|
||||
κατά
|
||||
κατα
|
||||
κατι
|
||||
κατιτι
|
||||
κατοπιν
|
||||
κατω
|
||||
κατὰ
|
||||
καὶ
|
||||
κι
|
||||
κιολας
|
||||
κλπ
|
||||
κοντα
|
||||
κτλ
|
||||
κυριως
|
||||
κἀν
|
||||
κἂν
|
||||
λιγακι
|
||||
λιγο
|
||||
λιγωτερο
|
||||
λογω
|
||||
λοιπα
|
||||
λοιπον
|
||||
μέν
|
||||
μέσα
|
||||
μή
|
||||
μήτε
|
||||
μία
|
||||
μα
|
||||
μαζι
|
||||
μακαρι
|
||||
μακρυα
|
||||
μαλιστα
|
||||
μαλλον
|
||||
μας
|
||||
με
|
||||
μεθ
|
||||
μεθαυριο
|
||||
μειον
|
||||
μελει
|
||||
μελλεται
|
||||
μεμιας
|
||||
μεν
|
||||
μερικα
|
||||
μερικες
|
||||
μερικοι
|
||||
μερικους
|
||||
μερικων
|
||||
μεσα
|
||||
μετ
|
||||
μετά
|
||||
μετα
|
||||
μεταξυ
|
||||
μετὰ
|
||||
μεχρι
|
||||
μη
|
||||
μην
|
||||
μηπως
|
||||
μητε
|
||||
μη∆ε
|
||||
μιά
|
||||
μια
|
||||
μιαν
|
||||
μιας
|
||||
μολις
|
||||
μολονοτι
|
||||
μοναχα
|
||||
μονες
|
||||
μονη
|
||||
μονην
|
||||
μονης
|
||||
μονο
|
||||
μονοι
|
||||
μονομιας
|
||||
μονος
|
||||
μονου
|
||||
μονους
|
||||
μονων
|
||||
μου
|
||||
μπορει
|
||||
μπορουν
|
||||
μπραβο
|
||||
μπρος
|
||||
μἐν
|
||||
μὲν
|
||||
μὴ
|
||||
μὴν
|
||||
να
|
||||
ναι
|
||||
νωρις
|
||||
ξανα
|
||||
ξαφνικα
|
||||
ο
|
||||
οι
|
||||
ολα
|
||||
ολες
|
||||
ολη
|
||||
ολην
|
||||
ολης
|
||||
ολο
|
||||
ολογυρα
|
||||
ολοι
|
||||
ολον
|
||||
ολονεν
|
||||
ολος
|
||||
ολοτελα
|
||||
ολου
|
||||
ολους
|
||||
ολων
|
||||
ολως
|
||||
ολως∆ιολου
|
||||
ομως
|
||||
ομωσ
|
||||
οποια
|
||||
οποιαν
|
||||
οποιαν∆ηποτε
|
||||
οποιας
|
||||
οποιας∆ηποτε
|
||||
οποια∆ηποτε
|
||||
οποιες
|
||||
οποιες∆ηποτε
|
||||
οποιο
|
||||
οποιοι
|
||||
οποιον
|
||||
οποιον∆ηποτε
|
||||
οποιος
|
||||
οποιος∆ηποτε
|
||||
οποιου
|
||||
οποιους
|
||||
οποιους∆ηποτε
|
||||
οποιου∆ηποτε
|
||||
οποιο∆ηποτε
|
||||
οποιων
|
||||
οποιων∆ηποτε
|
||||
οποι∆ηποτε
|
||||
οποτε
|
||||
οποτε∆ηποτε
|
||||
οπου
|
||||
οπου∆ηποτε
|
||||
οπως
|
||||
οπωσ
|
||||
ορισμενα
|
||||
ορισμενες
|
||||
ορισμενων
|
||||
ορισμενως
|
||||
οσα
|
||||
οσα∆ηποτε
|
||||
οσες
|
||||
οσες∆ηποτε
|
||||
οση
|
||||
οσην
|
||||
οσην∆ηποτε
|
||||
οσης
|
||||
οσης∆ηποτε
|
||||
οση∆ηποτε
|
||||
οσο
|
||||
οσοι
|
||||
οσοι∆ηποτε
|
||||
οσον
|
||||
οσον∆ηποτε
|
||||
οσος
|
||||
οσος∆ηποτε
|
||||
οσου
|
||||
οσους
|
||||
οσους∆ηποτε
|
||||
οσου∆ηποτε
|
||||
οσο∆ηποτε
|
||||
οσων
|
||||
οσων∆ηποτε
|
||||
οταν
|
||||
οτι
|
||||
οτι∆ηποτε
|
||||
οτου
|
||||
ου
|
||||
ουτε
|
||||
ου∆ε
|
||||
οχι
|
||||
οἱ
|
||||
οἳ
|
||||
οἷς
|
||||
οὐ
|
||||
οὐδ
|
||||
οὐδέ
|
||||
οὐδείσ
|
||||
οὐδεὶς
|
||||
οὐδὲ
|
||||
οὐδὲν
|
||||
οὐκ
|
||||
οὐχ
|
||||
οὐχὶ
|
||||
οὓς
|
||||
οὔτε
|
||||
οὕτω
|
||||
οὕτως
|
||||
οὕτωσ
|
||||
οὖν
|
||||
οὗ
|
||||
οὗτος
|
||||
οὗτοσ
|
||||
παλι
|
||||
παντοτε
|
||||
παντου
|
||||
παντως
|
||||
παρ
|
||||
παρά
|
||||
παρα
|
||||
παρὰ
|
||||
περί
|
||||
περα
|
||||
περι
|
||||
περιπου
|
||||
περισσοτερο
|
||||
περσι
|
||||
περυσι
|
||||
περὶ
|
||||
πια
|
||||
πιθανον
|
||||
πιο
|
||||
πισω
|
||||
πλαι
|
||||
πλεον
|
||||
πλην
|
||||
ποια
|
||||
ποιαν
|
||||
ποιας
|
||||
ποιες
|
||||
ποιεσ
|
||||
ποιο
|
||||
ποιοι
|
||||
ποιον
|
||||
ποιος
|
||||
ποιοσ
|
||||
ποιου
|
||||
ποιους
|
||||
ποιουσ
|
||||
ποιων
|
||||
πολυ
|
||||
ποσες
|
||||
ποση
|
||||
ποσην
|
||||
ποσης
|
||||
ποσοι
|
||||
ποσος
|
||||
ποσους
|
||||
ποτε
|
||||
που
|
||||
πουθε
|
||||
πουθενα
|
||||
ποῦ
|
||||
πρεπει
|
||||
πριν
|
||||
προ
|
||||
προκειμενου
|
||||
προκειται
|
||||
προπερσι
|
||||
προς
|
||||
προσ
|
||||
προτου
|
||||
προχθες
|
||||
προχτες
|
||||
πρωτυτερα
|
||||
πρόσ
|
||||
πρὸ
|
||||
πρὸς
|
||||
πως
|
||||
πωσ
|
||||
σαν
|
||||
σας
|
||||
σε
|
||||
σεις
|
||||
σημερα
|
||||
σιγα
|
||||
σου
|
||||
στα
|
||||
στη
|
||||
στην
|
||||
στης
|
||||
στις
|
||||
στο
|
||||
στον
|
||||
στου
|
||||
στους
|
||||
στων
|
||||
συγχρονως
|
||||
συν
|
||||
συναμα
|
||||
συνεπως
|
||||
συνηθως
|
||||
συχνα
|
||||
συχνας
|
||||
συχνες
|
||||
συχνη
|
||||
συχνην
|
||||
συχνης
|
||||
συχνο
|
||||
συχνοι
|
||||
συχνον
|
||||
συχνος
|
||||
συχνου
|
||||
συχνους
|
||||
συχνων
|
||||
συχνως
|
||||
σχε∆ον
|
||||
σωστα
|
||||
σόσ
|
||||
σύ
|
||||
σύν
|
||||
σὸς
|
||||
σὺ
|
||||
σὺν
|
||||
τά
|
||||
τήν
|
||||
τί
|
||||
τίς
|
||||
τίσ
|
||||
τα
|
||||
ταυτα
|
||||
ταυτες
|
||||
ταυτη
|
||||
ταυτην
|
||||
ταυτης
|
||||
ταυτο,ταυτον
|
||||
ταυτος
|
||||
ταυτου
|
||||
ταυτων
|
||||
ταχα
|
||||
ταχατε
|
||||
ταῖς
|
||||
τα∆ε
|
||||
τε
|
||||
τελικα
|
||||
τελικως
|
||||
τες
|
||||
τετοια
|
||||
τετοιαν
|
||||
τετοιας
|
||||
τετοιες
|
||||
τετοιο
|
||||
τετοιοι
|
||||
τετοιον
|
||||
τετοιος
|
||||
τετοιου
|
||||
τετοιους
|
||||
τετοιων
|
||||
τη
|
||||
την
|
||||
της
|
||||
τησ
|
||||
τι
|
||||
τινα
|
||||
τιποτα
|
||||
τιποτε
|
||||
τις
|
||||
τισ
|
||||
το
|
||||
τοί
|
||||
τοι
|
||||
τοιοῦτος
|
||||
τοιοῦτοσ
|
||||
τον
|
||||
τος
|
||||
τοσα
|
||||
τοσες
|
||||
τοση
|
||||
τοσην
|
||||
τοσης
|
||||
τοσο
|
||||
τοσοι
|
||||
τοσον
|
||||
τοσος
|
||||
τοσου
|
||||
τοσους
|
||||
τοσων
|
||||
τοτε
|
||||
του
|
||||
τουλαχιστο
|
||||
τουλαχιστον
|
||||
τους
|
||||
τουτα
|
||||
τουτες
|
||||
τουτη
|
||||
τουτην
|
||||
τουτης
|
||||
τουτο
|
||||
τουτοι
|
||||
τουτοις
|
||||
τουτον
|
||||
τουτος
|
||||
τουτου
|
||||
τουτους
|
||||
τουτων
|
||||
τούσ
|
||||
τοὺς
|
||||
τοῖς
|
||||
τοῦ
|
||||
τυχον
|
||||
των
|
||||
τωρα
|
||||
τό
|
||||
τόν
|
||||
τότε
|
||||
τὰ
|
||||
τὰς
|
||||
τὴν
|
||||
τὸ
|
||||
τὸν
|
||||
τῆς
|
||||
τῆσ
|
||||
τῇ
|
||||
τῶν
|
||||
τῷ
|
||||
υπ
|
||||
υπερ
|
||||
υπο
|
||||
υποψη
|
||||
υποψιν
|
||||
υπό
|
||||
υστερα
|
||||
φετος
|
||||
χαμηλα
|
||||
χθες
|
||||
χτες
|
||||
χωρις
|
||||
χωριστα
|
||||
ψηλα
|
||||
ω
|
||||
ωραια
|
||||
ως
|
||||
ωσ
|
||||
ωσαν
|
||||
ωσοτου
|
||||
ωσπου
|
||||
ωστε
|
||||
ωστοσο
|
||||
ωχ
|
||||
ἀλλ'
|
||||
ἀλλά
|
||||
ἀλλὰ
|
||||
ἀλλ’
|
||||
ἀπ
|
||||
ἀπό
|
||||
ἀπὸ
|
||||
ἀφ
|
||||
ἂν
|
||||
ἃ
|
||||
ἄλλος
|
||||
ἄλλοσ
|
||||
ἄν
|
||||
ἄρα
|
||||
ἅμα
|
||||
ἐάν
|
||||
ἐγώ
|
||||
ἐγὼ
|
||||
ἐκ
|
||||
ἐμόσ
|
||||
ἐμὸς
|
||||
ἐν
|
||||
ἐξ
|
||||
ἐπί
|
||||
ἐπεὶ
|
||||
ἐπὶ
|
||||
ἐστι
|
||||
ἐφ
|
||||
ἐὰν
|
||||
ἑαυτοῦ
|
||||
ἔτι
|
||||
ἡ
|
||||
ἢ
|
||||
ἣ
|
||||
ἤ
|
||||
ἥ
|
||||
ἧς
|
||||
ἵνα
|
||||
ὁ
|
||||
ὃ
|
||||
ὃν
|
||||
ὃς
|
||||
ὅ
|
||||
ὅδε
|
||||
ὅθεν
|
||||
ὅπερ
|
||||
ὅς
|
||||
ὅσ
|
||||
ὅστις
|
||||
ὅστισ
|
||||
ὅτε
|
||||
ὅτι
|
||||
ὑμόσ
|
||||
ὑπ
|
||||
ὑπέρ
|
||||
ὑπό
|
||||
ὑπὲρ
|
||||
ὑπὸ
|
||||
ὡς
|
||||
ὡσ
|
||||
ὥς
|
||||
ὥστε
|
||||
ὦ
|
||||
ᾧ
|
||||
∆α
|
||||
∆ε
|
||||
∆εινα
|
||||
∆εν
|
||||
∆εξια
|
||||
∆ηθεν
|
||||
∆ηλα∆η
|
||||
∆ι
|
||||
∆ια
|
||||
∆ιαρκως
|
||||
∆ικα
|
||||
∆ικο
|
||||
∆ικοι
|
||||
∆ικος
|
||||
∆ικου
|
||||
∆ικους
|
||||
∆ιολου
|
||||
∆ιπλα
|
||||
∆ιχως
|
|
@ -0,0 +1,655 @@
|
|||
a
|
||||
abbastanza
|
||||
abbia
|
||||
abbiamo
|
||||
abbiano
|
||||
abbiate
|
||||
accidenti
|
||||
ad
|
||||
adesso
|
||||
affinche
|
||||
agl
|
||||
agli
|
||||
ahime
|
||||
ahimã¨
|
||||
ahimè
|
||||
ai
|
||||
al
|
||||
alcuna
|
||||
alcuni
|
||||
alcuno
|
||||
all
|
||||
alla
|
||||
alle
|
||||
allo
|
||||
allora
|
||||
altre
|
||||
altri
|
||||
altrimenti
|
||||
altro
|
||||
altrove
|
||||
altrui
|
||||
anche
|
||||
ancora
|
||||
anni
|
||||
anno
|
||||
ansa
|
||||
anticipo
|
||||
assai
|
||||
attesa
|
||||
attraverso
|
||||
avanti
|
||||
avemmo
|
||||
avendo
|
||||
avente
|
||||
aver
|
||||
avere
|
||||
averlo
|
||||
avesse
|
||||
avessero
|
||||
avessi
|
||||
avessimo
|
||||
aveste
|
||||
avesti
|
||||
avete
|
||||
aveva
|
||||
avevamo
|
||||
avevano
|
||||
avevate
|
||||
avevi
|
||||
avevo
|
||||
avrai
|
||||
avranno
|
||||
avrebbe
|
||||
avrebbero
|
||||
avrei
|
||||
avremmo
|
||||
avremo
|
||||
avreste
|
||||
avresti
|
||||
avrete
|
||||
avrà
|
||||
avrò
|
||||
avuta
|
||||
avute
|
||||
avuti
|
||||
avuto
|
||||
basta
|
||||
ben
|
||||
bene
|
||||
benissimo
|
||||
berlusconi
|
||||
brava
|
||||
bravo
|
||||
buono
|
||||
c
|
||||
casa
|
||||
caso
|
||||
cento
|
||||
certa
|
||||
certe
|
||||
certi
|
||||
certo
|
||||
che
|
||||
chi
|
||||
chicchessia
|
||||
chiunque
|
||||
ci
|
||||
ciascuna
|
||||
ciascuno
|
||||
cima
|
||||
cinque
|
||||
cio
|
||||
cioe
|
||||
cioã¨
|
||||
cioè
|
||||
circa
|
||||
citta
|
||||
città
|
||||
cittã
|
||||
ciã²
|
||||
ciò
|
||||
co
|
||||
codesta
|
||||
codesti
|
||||
codesto
|
||||
cogli
|
||||
coi
|
||||
col
|
||||
colei
|
||||
coll
|
||||
coloro
|
||||
colui
|
||||
come
|
||||
cominci
|
||||
comprare
|
||||
comunque
|
||||
con
|
||||
concernente
|
||||
conciliarsi
|
||||
conclusione
|
||||
consecutivi
|
||||
consecutivo
|
||||
consiglio
|
||||
contro
|
||||
cortesia
|
||||
cos
|
||||
cosa
|
||||
cosi
|
||||
cosã¬
|
||||
così
|
||||
cui
|
||||
d
|
||||
da
|
||||
dagl
|
||||
dagli
|
||||
dai
|
||||
dal
|
||||
dall
|
||||
dalla
|
||||
dalle
|
||||
dallo
|
||||
dappertutto
|
||||
davanti
|
||||
degl
|
||||
degli
|
||||
dei
|
||||
del
|
||||
dell
|
||||
della
|
||||
delle
|
||||
dello
|
||||
dentro
|
||||
detto
|
||||
deve
|
||||
devo
|
||||
di
|
||||
dice
|
||||
dietro
|
||||
dire
|
||||
dirimpetto
|
||||
diventa
|
||||
diventare
|
||||
diventato
|
||||
dopo
|
||||
doppio
|
||||
dov
|
||||
dove
|
||||
dovra
|
||||
dovrà
|
||||
dovrã
|
||||
dovunque
|
||||
due
|
||||
dunque
|
||||
durante
|
||||
e
|
||||
ebbe
|
||||
ebbero
|
||||
ebbi
|
||||
ecc
|
||||
ecco
|
||||
ed
|
||||
effettivamente
|
||||
egli
|
||||
ella
|
||||
entrambi
|
||||
eppure
|
||||
era
|
||||
erano
|
||||
eravamo
|
||||
eravate
|
||||
eri
|
||||
ero
|
||||
esempio
|
||||
esse
|
||||
essendo
|
||||
esser
|
||||
essere
|
||||
essi
|
||||
ex
|
||||
fa
|
||||
faccia
|
||||
facciamo
|
||||
facciano
|
||||
facciate
|
||||
faccio
|
||||
facemmo
|
||||
facendo
|
||||
facesse
|
||||
facessero
|
||||
facessi
|
||||
facessimo
|
||||
faceste
|
||||
facesti
|
||||
faceva
|
||||
facevamo
|
||||
facevano
|
||||
facevate
|
||||
facevi
|
||||
facevo
|
||||
fai
|
||||
fanno
|
||||
farai
|
||||
faranno
|
||||
fare
|
||||
farebbe
|
||||
farebbero
|
||||
farei
|
||||
faremmo
|
||||
faremo
|
||||
fareste
|
||||
faresti
|
||||
farete
|
||||
farà
|
||||
farò
|
||||
fatto
|
||||
favore
|
||||
fece
|
||||
fecero
|
||||
feci
|
||||
fin
|
||||
finalmente
|
||||
finche
|
||||
fine
|
||||
fino
|
||||
forse
|
||||
forza
|
||||
fosse
|
||||
fossero
|
||||
fossi
|
||||
fossimo
|
||||
foste
|
||||
fosti
|
||||
fra
|
||||
frattempo
|
||||
fu
|
||||
fui
|
||||
fummo
|
||||
fuori
|
||||
furono
|
||||
futuro
|
||||
generale
|
||||
gente
|
||||
gia
|
||||
giacche
|
||||
giorni
|
||||
giorno
|
||||
giu
|
||||
già
|
||||
giã
|
||||
gli
|
||||
gliela
|
||||
gliele
|
||||
glieli
|
||||
glielo
|
||||
gliene
|
||||
governo
|
||||
grande
|
||||
grazie
|
||||
gruppo
|
||||
ha
|
||||
haha
|
||||
hai
|
||||
hanno
|
||||
ho
|
||||
i
|
||||
ie
|
||||
ieri
|
||||
il
|
||||
improvviso
|
||||
in
|
||||
inc
|
||||
indietro
|
||||
infatti
|
||||
inoltre
|
||||
insieme
|
||||
intanto
|
||||
intorno
|
||||
invece
|
||||
io
|
||||
l
|
||||
la
|
||||
lasciato
|
||||
lato
|
||||
lavoro
|
||||
le
|
||||
lei
|
||||
li
|
||||
lo
|
||||
lontano
|
||||
loro
|
||||
lui
|
||||
lungo
|
||||
luogo
|
||||
là
|
||||
lã
|
||||
ma
|
||||
macche
|
||||
magari
|
||||
maggior
|
||||
mai
|
||||
male
|
||||
malgrado
|
||||
malissimo
|
||||
mancanza
|
||||
me
|
||||
medesimo
|
||||
mediante
|
||||
meglio
|
||||
meno
|
||||
mentre
|
||||
mesi
|
||||
mezzo
|
||||
mi
|
||||
mia
|
||||
mie
|
||||
miei
|
||||
mila
|
||||
miliardi
|
||||
milioni
|
||||
minimi
|
||||
ministro
|
||||
mio
|
||||
modo
|
||||
molta
|
||||
molti
|
||||
moltissimo
|
||||
molto
|
||||
momento
|
||||
mondo
|
||||
mosto
|
||||
nazionale
|
||||
ne
|
||||
negl
|
||||
negli
|
||||
nei
|
||||
nel
|
||||
nell
|
||||
nella
|
||||
nelle
|
||||
nello
|
||||
nemmeno
|
||||
neppure
|
||||
nessun
|
||||
nessuna
|
||||
nessuno
|
||||
niente
|
||||
no
|
||||
noi
|
||||
nome
|
||||
non
|
||||
nondimeno
|
||||
nonostante
|
||||
nonsia
|
||||
nostra
|
||||
nostre
|
||||
nostri
|
||||
nostro
|
||||
novanta
|
||||
nove
|
||||
nulla
|
||||
nuovi
|
||||
nuovo
|
||||
o
|
||||
od
|
||||
oggi
|
||||
ogni
|
||||
ognuna
|
||||
ognuno
|
||||
oltre
|
||||
oppure
|
||||
ora
|
||||
ore
|
||||
osi
|
||||
ossia
|
||||
ottanta
|
||||
otto
|
||||
paese
|
||||
parecchi
|
||||
parecchie
|
||||
parecchio
|
||||
parte
|
||||
partendo
|
||||
peccato
|
||||
peggio
|
||||
per
|
||||
perche
|
||||
perchã¨
|
||||
perchè
|
||||
perché
|
||||
percio
|
||||
perciã²
|
||||
perciò
|
||||
perfino
|
||||
pero
|
||||
persino
|
||||
persone
|
||||
perã²
|
||||
però
|
||||
piedi
|
||||
pieno
|
||||
piglia
|
||||
piu
|
||||
piuttosto
|
||||
piã¹
|
||||
più
|
||||
po
|
||||
pochissimo
|
||||
poco
|
||||
poi
|
||||
poiche
|
||||
possa
|
||||
possedere
|
||||
posteriore
|
||||
posto
|
||||
potrebbe
|
||||
preferibilmente
|
||||
presa
|
||||
prima
|
||||
primo
|
||||
principalmente
|
||||
probabilmente
|
||||
promesso
|
||||
proprio
|
||||
puo
|
||||
pure
|
||||
purtroppo
|
||||
puã²
|
||||
può
|
||||
qua
|
||||
qualche
|
||||
qualcosa
|
||||
qualcuna
|
||||
qualcuno
|
||||
quale
|
||||
quali
|
||||
qualunque
|
||||
quando
|
||||
quanta
|
||||
quante
|
||||
quanti
|
||||
quanto
|
||||
quantunque
|
||||
quarto
|
||||
quasi
|
||||
quattro
|
||||
quel
|
||||
quella
|
||||
quelle
|
||||
quelli
|
||||
quello
|
||||
quest
|
||||
questa
|
||||
queste
|
||||
questi
|
||||
questo
|
||||
qui
|
||||
quindi
|
||||
quinto
|
||||
realmente
|
||||
recente
|
||||
recentemente
|
||||
registrazione
|
||||
relativo
|
||||
riecco
|
||||
rispetto
|
||||
salvo
|
||||
sara
|
||||
sarai
|
||||
saranno
|
||||
sarebbe
|
||||
sarebbero
|
||||
sarei
|
||||
saremmo
|
||||
saremo
|
||||
sareste
|
||||
saresti
|
||||
sarete
|
||||
sarà
|
||||
sarã
|
||||
sarò
|
||||
scola
|
||||
scopo
|
||||
scorso
|
||||
se
|
||||
secondo
|
||||
seguente
|
||||
seguito
|
||||
sei
|
||||
sembra
|
||||
sembrare
|
||||
sembrato
|
||||
sembrava
|
||||
sembri
|
||||
sempre
|
||||
senza
|
||||
sette
|
||||
si
|
||||
sia
|
||||
siamo
|
||||
siano
|
||||
siate
|
||||
siete
|
||||
sig
|
||||
solito
|
||||
solo
|
||||
soltanto
|
||||
sono
|
||||
sopra
|
||||
soprattutto
|
||||
sotto
|
||||
spesso
|
||||
srl
|
||||
sta
|
||||
stai
|
||||
stando
|
||||
stanno
|
||||
starai
|
||||
staranno
|
||||
starebbe
|
||||
starebbero
|
||||
starei
|
||||
staremmo
|
||||
staremo
|
||||
stareste
|
||||
staresti
|
||||
starete
|
||||
starà
|
||||
starò
|
||||
stata
|
||||
stati
|
||||
stava
|
||||
stavamo
|
||||
stavano
|
||||
stavate
|
||||
stavi
|
||||
stavo
|
||||
stemmo
|
||||
stessa
|
||||
stesse
|
||||
stessero
|
||||
stessi
|
||||
stessimo
|
||||
stesso
|
||||
steste
|
||||
stesti
|
||||
stette
|
||||
stettero
|
||||
stetti
|
||||
stia
|
||||
stiamo
|
||||
stiano
|
||||
stiate
|
||||
sto
|
||||
su
|
||||
sua
|
||||
subito
|
||||
successivamente
|
||||
successivo
|
||||
sue
|
||||
sugl
|
||||
sugli
|
||||
sui
|
||||
sul
|
||||
sull
|
||||
sulla
|
||||
sulle
|
||||
sullo
|
||||
suo
|
||||
suoi
|
||||
tale
|
||||
tali
|
||||
talvolta
|
||||
tanto
|
||||
te
|
||||
tempo
|
||||
terzo
|
||||
th
|
||||
ti
|
||||
titolo
|
||||
tra
|
||||
tranne
|
||||
tre
|
||||
trenta
|
||||
triplo
|
||||
troppo
|
||||
trovato
|
||||
tu
|
||||
tua
|
||||
tue
|
||||
tuo
|
||||
tuoi
|
||||
tutta
|
||||
tuttavia
|
||||
tutte
|
||||
tutti
|
||||
tutto
|
||||
uguali
|
||||
ulteriore
|
||||
ultimo
|
||||
un
|
||||
una
|
||||
uno
|
||||
uomo
|
||||
va
|
||||
vai
|
||||
vale
|
||||
vari
|
||||
varia
|
||||
varie
|
||||
vario
|
||||
verso
|
||||
vi
|
||||
via
|
||||
vicino
|
||||
visto
|
||||
vita
|
||||
voi
|
||||
volta
|
||||
volte
|
||||
vostra
|
||||
vostre
|
||||
vostri
|
||||
vostro
|
||||
ã¨
|
||||
è
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue