From 3adedd0a681e8a352fe96e850eed78ad227b210a Mon Sep 17 00:00:00 2001 From: "michele.artini" Date: Fri, 17 Jul 2020 11:58:11 +0200 Subject: [PATCH 01/21] trust truncated to 3 decimals --- .../dhp/oa/graph/raw/MigrateDbEntitiesApplication.java | 7 +++++-- .../graph/raw/datasourceorganization_resultset_entry.json | 4 ++-- .../dhp/oa/graph/raw/datasources_resultset_entry.json | 4 ++-- .../dhp/oa/graph/raw/organizations_resultset_entry.json | 4 ++-- .../oa/graph/raw/projectorganization_resultset_entry.json | 4 ++-- .../dnetlib/dhp/oa/graph/raw/projects_resultset_entry.json | 4 ++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java index da2ba4723..3a6ab25f0 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java @@ -496,9 +496,12 @@ public class MigrateDbEntitiesApplication extends AbstractMigrationApplication i final Boolean deletedbyinference = rs.getBoolean("deletedbyinference"); final String inferenceprovenance = rs.getString("inferenceprovenance"); final Boolean inferred = rs.getBoolean("inferred"); - final String trust = rs.getString("trust"); + + final double trust = rs.getDouble("trust"); + return dataInfo( - deletedbyinference, inferenceprovenance, inferred, false, ENTITYREGISTRY_PROVENANCE_ACTION, trust); + deletedbyinference, inferenceprovenance, inferred, false, ENTITYREGISTRY_PROVENANCE_ACTION, + String.format("%.3f", trust)); } private Qualifier prepareQualifierSplitting(final String s) { diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasourceorganization_resultset_entry.json b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasourceorganization_resultset_entry.json index 2baf7c8f1..06b0d483b 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasourceorganization_resultset_entry.json +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasourceorganization_resultset_entry.json @@ -31,8 +31,8 @@ }, { "field": "trust", - "type": "string", - "value": "0.9" + "type": "double", + "value": 0.9 }, { "field": "inferenceprovenance", diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasources_resultset_entry.json b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasources_resultset_entry.json index 0f1da7095..23809bb85 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasources_resultset_entry.json +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/datasources_resultset_entry.json @@ -114,8 +114,8 @@ }, { "field": "trust", - "type": "string", - "value": "0.9" + "type": "double", + "value": 0.9 }, { "field": "inferenceprovenance", diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/organizations_resultset_entry.json b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/organizations_resultset_entry.json index 38657a1e1..811a9079f 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/organizations_resultset_entry.json +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/organizations_resultset_entry.json @@ -96,8 +96,8 @@ }, { "field": "trust", - "type": "string", - "value": "0.9" + "type": "double", + "value": 0.9 }, { "field": "inferenceprovenance", diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projectorganization_resultset_entry.json b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projectorganization_resultset_entry.json index 4311086e7..a3305926d 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projectorganization_resultset_entry.json +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projectorganization_resultset_entry.json @@ -41,8 +41,8 @@ }, { "field": "trust", - "type": "string", - "value": "0.9" + "type": "double", + "value": 0.9 }, { "field": "inferenceprovenance", diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projects_resultset_entry.json b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projects_resultset_entry.json index d6109cac1..37480fc94 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projects_resultset_entry.json +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/projects_resultset_entry.json @@ -86,8 +86,8 @@ }, { "field": "trust", - "type": "string", - "value": "0.9" + "type": "double", + "value": 0.9 }, { "field": "inferenceprovenance", From 13e36a4da0297cc6186e9e014cdec7c0e59a284d Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Fri, 13 Nov 2020 10:05:02 +0100 Subject: [PATCH 02/21] WIP: added oozie workflow for grouping graph entities by id --- .../dhp/schema/oaf/OafMapperUtils.java | 2 + .../dhp/schema/oaf/ResultTypeComparator.java | 2 + .../groupbyid/DispatchEntitiesSparkJob.java | 87 ++++++ .../GroupEntitiesAndRelationsSparkJob.java | 186 ++++++++++++ ...kJob.java => MergeGraphTableSparkJob.java} | 4 +- .../raw/GenerateEntitiesApplication.java | 31 +- .../oa/graph/raw/common/OafMapperUtils.java | 273 ------------------ .../dispatch_entities_bytype_parameters.json | 20 ++ .../group_graph_entities_parameters.json | 20 ++ .../groupbyid/oozie_app/config-default.xml | 18 ++ .../oa/graph/groupbyid/oozie_app/workflow.xml | 271 +++++++++++++++++ .../dhp/oa/graph/merge/oozie_app/workflow.xml | 16 +- ....java => MergeGraphTableSparkJobTest.java} | 14 +- .../raw/GenerateEntitiesApplicationTest.java | 99 +++++++ 14 files changed, 727 insertions(+), 316 deletions(-) create mode 100644 dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java create mode 100644 dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java rename dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/{MergeGraphSparkJob.java => MergeGraphTableSparkJob.java} (98%) delete mode 100644 dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/OafMapperUtils.java create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml create mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml rename dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/{MergeGraphSparkJobTest.java => MergeGraphTableSparkJobTest.java} (90%) create mode 100644 dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplicationTest.java diff --git a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java new file mode 100644 index 000000000..6ba918069 --- /dev/null +++ b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java @@ -0,0 +1,2 @@ +package eu.dnetlib.dhp.schema.oaf;public class OafMapperUtils { +} diff --git a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java new file mode 100644 index 000000000..a2e64b83b --- /dev/null +++ b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java @@ -0,0 +1,2 @@ +package eu.dnetlib.dhp.schema.oaf;public class ResultTypeComparator { +} diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java new file mode 100644 index 000000000..6b90e9971 --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java @@ -0,0 +1,87 @@ + +package eu.dnetlib.dhp.oa.graph.fuse; + +import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.common.HdfsSupport; +import eu.dnetlib.dhp.oa.graph.raw.MigrateMongoMdstoresApplication; +import eu.dnetlib.dhp.schema.common.ModelSupport; +import eu.dnetlib.dhp.schema.oaf.Oaf; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.function.FilterFunction; +import org.apache.spark.api.java.function.MapFunction; +import org.apache.spark.sql.Encoders; +import org.apache.spark.sql.SaveMode; +import org.apache.spark.sql.SparkSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; + +public class DispatchEntitiesSparkJob { + + private static final Logger log = LoggerFactory.getLogger(DispatchEntitiesSparkJob.class); + + public static void main(final String[] args) throws Exception { + final ArgumentApplicationParser parser = new ArgumentApplicationParser( + IOUtils + .toString( + MigrateMongoMdstoresApplication.class + .getResourceAsStream( + "/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json"))); + parser.parseArgument(args); + + Boolean isSparkSessionManaged = Optional + .ofNullable(parser.get("isSparkSessionManaged")) + .map(Boolean::valueOf) + .orElse(Boolean.TRUE); + log.info("isSparkSessionManaged: {}", isSparkSessionManaged); + + final String sourcePath = parser.get("sourcePath"); + final String targetPath = parser.get("graphRawPath"); + + SparkConf conf = new SparkConf(); + runWithSparkSession( + conf, + isSparkSessionManaged, + spark -> { + removeOutputDir(spark, targetPath); + ModelSupport.oafTypes + .values() + .forEach(clazz -> processEntity(spark, clazz, sourcePath, targetPath)); + }); + } + + private static void processEntity( + final SparkSession spark, + final Class clazz, + final String sourcePath, + final String targetPath) { + final String type = clazz.getSimpleName().toLowerCase(); + + log.info("Processing entities ({}) in file: {}", type, sourcePath); + + spark + .read() + .textFile(sourcePath) + .filter((FilterFunction) value -> isEntityType(value, type)) + .map( + (MapFunction) l -> StringUtils.substringAfter(l, "|"), + Encoders.STRING()) + .write() + .option("compression", "gzip") + .mode(SaveMode.Overwrite) + .text(targetPath + "/" + type); + } + + private static boolean isEntityType(final String line, final String type) { + return StringUtils.substringBefore(line, "|").equalsIgnoreCase(type); + } + + private static void removeOutputDir(SparkSession spark, String path) { + HdfsSupport.remove(path, spark.sparkContext().hadoopConfiguration()); + } +} diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java new file mode 100644 index 000000000..7ab8646ec --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java @@ -0,0 +1,186 @@ + +package eu.dnetlib.dhp.oa.graph.groupbyid; + +import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; +import static eu.dnetlib.dhp.utils.DHPUtils.toSeq; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.io.compress.GzipCodec; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.MapFunction; +import org.apache.spark.sql.*; +import org.apache.spark.sql.expressions.Aggregator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; + +import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.common.HdfsSupport; +import eu.dnetlib.dhp.schema.common.ModelSupport; +import eu.dnetlib.dhp.schema.oaf.*; +import scala.Tuple2; + +/** + * Groups the graph content by entity identifier to ensure ID uniqueness + */ +public class GroupEntitiesSparkJob { + + private static final Logger log = LoggerFactory.getLogger(GroupEntitiesSparkJob.class); + + private final static String ID_JPATH = "$.id"; + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + public static void main(String[] args) throws Exception { + + String jsonConfiguration = IOUtils + .toString( + GroupEntitiesSparkJob.class + .getResourceAsStream( + "/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json")); + final ArgumentApplicationParser parser = new ArgumentApplicationParser(jsonConfiguration); + parser.parseArgument(args); + + Boolean isSparkSessionManaged = Optional + .ofNullable(parser.get("isSparkSessionManaged")) + .map(Boolean::valueOf) + .orElse(Boolean.TRUE); + log.info("isSparkSessionManaged: {}", isSparkSessionManaged); + + String graphInputPath = parser.get("graphInputPath"); + log.info("graphInputPath: {}", graphInputPath); + + String outputPath = parser.get("outputPath"); + log.info("outputPath: {}", outputPath); + + SparkConf conf = new SparkConf(); + conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); + conf.registerKryoClasses(ModelSupport.getOafModelClasses()); + + runWithSparkSession( + conf, + isSparkSessionManaged, + spark -> { + HdfsSupport.remove(outputPath, spark.sparkContext().hadoopConfiguration()); + groupEntities(spark, graphInputPath, outputPath); + }); + } + + private static void groupEntities( + SparkSession spark, + String inputPath, + String outputPath) { + + TypedColumn aggregator = new GroupingAggregator().toColumn(); + final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); + spark + .read() + .textFile(toSeq(listEntityPaths(inputPath, sc))) + .map((MapFunction) s -> parseEntity(s), Encoders.kryo(Oaf.class)) + .groupByKey((MapFunction) oaf -> ModelSupport.idFn().apply(oaf), Encoders.STRING()) + .agg(aggregator) + .map((MapFunction, Oaf>) Tuple2::_2, Encoders.kryo(Oaf.class)) + .write() + .mode(SaveMode.Overwrite) + .save(outputPath); + } + + public static class GroupingAggregator extends Aggregator { + + @Override + public Oaf zero() { + return null; + } + + @Override + public Oaf reduce(Oaf b, Oaf a) { + return mergeAndGet(b, a); + } + + private Oaf mergeAndGet(Oaf b, Oaf a) { + if (Objects.nonNull(a) && Objects.nonNull(b)) { + return OafMapperUtils.merge(b, a); + } + return Objects.isNull(a) ? b : a; + } + + @Override + public Oaf merge(Oaf b, Oaf a) { + return mergeAndGet(b, a); + } + + @Override + public Oaf finish(Oaf j) { + return j; + } + + @Override + public Encoder bufferEncoder() { + return Encoders.kryo(Oaf.class); + } + + @Override + public Encoder outputEncoder() { + return Encoders.kryo(Oaf.class); + } + + } + + private static Oaf parseEntity(String s) { + String prefix = StringUtils.substringBefore(jPath(ID_JPATH, s), "|"); + try { + switch (prefix) { + case "10": + return OBJECT_MAPPER.readValue(s, Datasource.class); + case "20": + return OBJECT_MAPPER.readValue(s, Organization.class); + case "40": + return OBJECT_MAPPER.readValue(s, Project.class); + case "50": + String resultType = jPath("$.resulttype.classid", s); + switch (resultType) { + case "publication": + return OBJECT_MAPPER.readValue(s, Publication.class); + case "dataset": + return OBJECT_MAPPER.readValue(s, eu.dnetlib.dhp.schema.oaf.Dataset.class); + case "software": + return OBJECT_MAPPER.readValue(s, Software.class); + case "other": + return OBJECT_MAPPER.readValue(s, OtherResearchProduct.class); + default: + throw new IllegalArgumentException(String.format("invalid resultType: '%s'", resultType)); + } + default: + throw new IllegalArgumentException(String.format("invalid id prefix: '%s'", prefix)); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static List listEntityPaths(String inputPath, JavaSparkContext sc) { + return HdfsSupport + .listFiles(inputPath, sc.hadoopConfiguration()) + .stream() + .filter(p -> !p.contains("relation")) + .collect(Collectors.toList()); + } + + private static String jPath(final String path, final String json) { + Object o = JsonPath.read(json, path); + if (o instanceof String) + return (String) o; + throw new IllegalStateException(String.format("could not extract '%s' from:\n%s", path, json)); + } + +} diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJob.java similarity index 98% rename from dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJob.java rename to dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJob.java index 037683604..e53f4ca30 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJob.java @@ -33,9 +33,9 @@ import scala.Tuple2; * are picked preferring those from the BETA aggregator rather then from PROD. The identity of a relationship is defined * by eu.dnetlib.dhp.schema.common.ModelSupport#idFn() */ -public class MergeGraphSparkJob { +public class MergeGraphTableSparkJob { - private static final Logger log = LoggerFactory.getLogger(CleanGraphSparkJob.class); + private static final Logger log = LoggerFactory.getLogger(MergeGraphTableSparkJob.class); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java index 3568dc52a..99aa9c3f0 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java @@ -4,11 +4,9 @@ package eu.dnetlib.dhp.oa.graph.raw; import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -20,6 +18,7 @@ import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.sql.SparkSession; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,16 +28,7 @@ import eu.dnetlib.dhp.application.ArgumentApplicationParser; import eu.dnetlib.dhp.common.HdfsSupport; import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; import eu.dnetlib.dhp.schema.common.ModelSupport; -import eu.dnetlib.dhp.schema.oaf.Dataset; -import eu.dnetlib.dhp.schema.oaf.Datasource; -import eu.dnetlib.dhp.schema.oaf.Oaf; -import eu.dnetlib.dhp.schema.oaf.OafEntity; -import eu.dnetlib.dhp.schema.oaf.Organization; -import eu.dnetlib.dhp.schema.oaf.OtherResearchProduct; -import eu.dnetlib.dhp.schema.oaf.Project; -import eu.dnetlib.dhp.schema.oaf.Publication; -import eu.dnetlib.dhp.schema.oaf.Relation; -import eu.dnetlib.dhp.schema.oaf.Software; +import eu.dnetlib.dhp.schema.oaf.*; import eu.dnetlib.dhp.utils.ISLookupClientFactory; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; import scala.Tuple2; @@ -113,7 +103,7 @@ public class GenerateEntitiesApplication { inputRdd .mapToPair(oaf -> new Tuple2<>(ModelSupport.idFn().apply(oaf), oaf)) - .reduceByKey((o1, o2) -> merge(o1, o2)) + .reduceByKey((o1, o2) -> OafMapperUtils.merge(o1, o2)) .map(Tuple2::_2) .map( oaf -> oaf.getClass().getSimpleName().toLowerCase() @@ -122,17 +112,6 @@ public class GenerateEntitiesApplication { .saveAsTextFile(targetPath, GzipCodec.class); } - private static Oaf merge(final Oaf o1, final Oaf o2) { - if (ModelSupport.isSubClass(o1, OafEntity.class)) { - ((OafEntity) o1).mergeFrom((OafEntity) o2); - } else if (ModelSupport.isSubClass(o1, Relation.class)) { - ((Relation) o1).mergeFrom((Relation) o2); - } else { - throw new RuntimeException("invalid Oaf type:" + o1.getClass().getCanonicalName()); - } - return o1; - } - private static List convertToListOaf( final String id, final String s, diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/OafMapperUtils.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/OafMapperUtils.java deleted file mode 100644 index 84b29e3d4..000000000 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/OafMapperUtils.java +++ /dev/null @@ -1,273 +0,0 @@ - -package eu.dnetlib.dhp.oa.graph.raw.common; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; - -import eu.dnetlib.dhp.schema.oaf.DataInfo; -import eu.dnetlib.dhp.schema.oaf.ExtraInfo; -import eu.dnetlib.dhp.schema.oaf.Field; -import eu.dnetlib.dhp.schema.oaf.Journal; -import eu.dnetlib.dhp.schema.oaf.KeyValue; -import eu.dnetlib.dhp.schema.oaf.OAIProvenance; -import eu.dnetlib.dhp.schema.oaf.OriginDescription; -import eu.dnetlib.dhp.schema.oaf.Qualifier; -import eu.dnetlib.dhp.schema.oaf.StructuredProperty; -import eu.dnetlib.dhp.utils.DHPUtils; - -public class OafMapperUtils { - - public static KeyValue keyValue(final String k, final String v) { - final KeyValue kv = new KeyValue(); - kv.setKey(k); - kv.setValue(v); - return kv; - } - - public static List listKeyValues(final String... s) { - if (s.length % 2 > 0) { - throw new RuntimeException("Invalid number of parameters (k,v,k,v,....)"); - } - - final List list = new ArrayList<>(); - for (int i = 0; i < s.length; i += 2) { - list.add(keyValue(s[i], s[i + 1])); - } - return list; - } - - public static Field field(final T value, final DataInfo info) { - if (value == null || StringUtils.isBlank(value.toString())) { - return null; - } - - final Field field = new Field<>(); - field.setValue(value); - field.setDataInfo(info); - return field; - } - - public static List> listFields(final DataInfo info, final String... values) { - return Arrays - .stream(values) - .map(v -> field(v, info)) - .filter(Objects::nonNull) - .filter(distinctByKey(f -> f.getValue())) - .collect(Collectors.toList()); - } - - public static List> listFields(final DataInfo info, final List values) { - return values - .stream() - .map(v -> field(v, info)) - .filter(Objects::nonNull) - .filter(distinctByKey(f -> f.getValue())) - .collect(Collectors.toList()); - } - - public static Qualifier unknown(final String schemeid, final String schemename) { - return qualifier("UNKNOWN", "Unknown", schemeid, schemename); - } - - public static Qualifier qualifier( - final String classid, - final String classname, - final String schemeid, - final String schemename) { - final Qualifier q = new Qualifier(); - q.setClassid(classid); - q.setClassname(classname); - q.setSchemeid(schemeid); - q.setSchemename(schemename); - return q; - } - - public static StructuredProperty structuredProperty( - final String value, - final String classid, - final String classname, - final String schemeid, - final String schemename, - final DataInfo dataInfo) { - - return structuredProperty(value, qualifier(classid, classname, schemeid, schemename), dataInfo); - } - - public static StructuredProperty structuredProperty( - final String value, - final Qualifier qualifier, - final DataInfo dataInfo) { - if (value == null) { - return null; - } - final StructuredProperty sp = new StructuredProperty(); - sp.setValue(value); - sp.setQualifier(qualifier); - sp.setDataInfo(dataInfo); - return sp; - } - - public static ExtraInfo extraInfo( - final String name, - final String value, - final String typology, - final String provenance, - final String trust) { - final ExtraInfo info = new ExtraInfo(); - info.setName(name); - info.setValue(value); - info.setTypology(typology); - info.setProvenance(provenance); - info.setTrust(trust); - return info; - } - - public static OAIProvenance oaiIProvenance( - final String identifier, - final String baseURL, - final String metadataNamespace, - final Boolean altered, - final String datestamp, - final String harvestDate) { - - final OriginDescription desc = new OriginDescription(); - desc.setIdentifier(identifier); - desc.setBaseURL(baseURL); - desc.setMetadataNamespace(metadataNamespace); - desc.setAltered(altered); - desc.setDatestamp(datestamp); - desc.setHarvestDate(harvestDate); - - final OAIProvenance p = new OAIProvenance(); - p.setOriginDescription(desc); - - return p; - } - - public static Journal journal( - final String name, - final String issnPrinted, - final String issnOnline, - final String issnLinking, - final DataInfo dataInfo) { - return journal( - name, - issnPrinted, - issnOnline, - issnLinking, - null, - null, - null, - null, - null, - null, - null, - dataInfo); - } - - public static Journal journal( - final String name, - final String issnPrinted, - final String issnOnline, - final String issnLinking, - final String ep, - final String iss, - final String sp, - final String vol, - final String edition, - final String conferenceplace, - final String conferencedate, - final DataInfo dataInfo) { - - if (StringUtils.isNotBlank(name) - || StringUtils.isNotBlank(issnPrinted) - || StringUtils.isNotBlank(issnOnline) - || StringUtils.isNotBlank(issnLinking)) { - final Journal j = new Journal(); - j.setName(name); - j.setIssnPrinted(issnPrinted); - j.setIssnOnline(issnOnline); - j.setIssnLinking(issnLinking); - j.setEp(ep); - j.setIss(iss); - j.setSp(sp); - j.setVol(vol); - j.setEdition(edition); - j.setConferenceplace(conferenceplace); - j.setConferencedate(conferencedate); - j.setDataInfo(dataInfo); - return j; - } else { - return null; - } - } - - public static DataInfo dataInfo( - final Boolean deletedbyinference, - final String inferenceprovenance, - final Boolean inferred, - final Boolean invisible, - final Qualifier provenanceaction, - final String trust) { - final DataInfo d = new DataInfo(); - d.setDeletedbyinference(deletedbyinference); - d.setInferenceprovenance(inferenceprovenance); - d.setInferred(inferred); - d.setInvisible(invisible); - d.setProvenanceaction(provenanceaction); - d.setTrust(trust); - return d; - } - - public static String createOpenaireId( - final int prefix, - final String originalId, - final boolean to_md5) { - if (StringUtils.isBlank(originalId)) { - return null; - } else if (to_md5) { - final String nsPrefix = StringUtils.substringBefore(originalId, "::"); - final String rest = StringUtils.substringAfter(originalId, "::"); - return String.format("%s|%s::%s", prefix, nsPrefix, DHPUtils.md5(rest)); - } else { - return String.format("%s|%s", prefix, originalId); - } - } - - public static String createOpenaireId( - final String type, - final String originalId, - final boolean to_md5) { - switch (type) { - case "datasource": - return createOpenaireId(10, originalId, to_md5); - case "organization": - return createOpenaireId(20, originalId, to_md5); - case "person": - return createOpenaireId(30, originalId, to_md5); - case "project": - return createOpenaireId(40, originalId, to_md5); - default: - return createOpenaireId(50, originalId, to_md5); - } - } - - public static String asString(final Object o) { - return o == null ? "" : o.toString(); - } - - public static Predicate distinctByKey( - final Function keyExtractor) { - final Map seen = new ConcurrentHashMap<>(); - return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; - } -} diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json new file mode 100644 index 000000000..7d995f39a --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json @@ -0,0 +1,20 @@ +[ + { + "paramName": "issm", + "paramLongName": "isSparkSessionManaged", + "paramDescription": "when true will stop SparkSession after job execution", + "paramRequired": false + }, + { + "paramName": "s", + "paramLongName": "sourcePath", + "paramDescription": "the source path", + "paramRequired": true + }, + { + "paramName": "g", + "paramLongName": "graphRawPath", + "paramDescription": "the path of the graph Raw in hdfs", + "paramRequired": true + } +] \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json new file mode 100644 index 000000000..e65acb3c4 --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json @@ -0,0 +1,20 @@ +[ + { + "paramName": "issm", + "paramLongName": "isSparkSessionManaged", + "paramDescription": "when true will stop SparkSession after job execution", + "paramRequired": false + }, + { + "paramName": "gin", + "paramLongName": "graphInputPath", + "paramDescription": "the graph root path", + "paramRequired": true + }, + { + "paramName": "out", + "paramLongName": "outputPath", + "paramDescription": "the output merged graph root path", + "paramRequired": true + } +] \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml new file mode 100644 index 000000000..2e0ed9aee --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml @@ -0,0 +1,18 @@ + + + jobTracker + yarnRM + + + nameNode + hdfs://nameservice1 + + + oozie.use.system.libpath + true + + + oozie.action.sharelib.for.spark + spark2 + + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml new file mode 100644 index 000000000..3715d097d --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml @@ -0,0 +1,271 @@ + + + + + graphInputPath + the graph root input path + + + outputPath + the graph root output path + + + + sparkDriverMemory + memory for driver process + + + sparkExecutorMemory + memory for individual executor + + + sparkExecutorCores + number of cores used by single executor + + + oozieActionShareLibForSpark2 + oozie action sharelib for spark 2.* + + + spark2ExtraListeners + com.cloudera.spark.lineage.NavigatorAppListener + spark 2.* extra listeners classname + + + spark2SqlQueryExecutionListeners + com.cloudera.spark.lineage.NavigatorQueryListener + spark 2.* sql query execution listeners classname + + + spark2YarnHistoryServerAddress + spark 2.* yarn history server address + + + spark2EventLogDir + spark 2.* event log dir location + + + + + + + Action failed, error message[${wf:errorMessage(wf:lastErrorNode())}] + + + + + yarn + cluster + Fuse graph entities by ID + eu.dnetlib.dhp.oa.graph.fuse.FuseGraphResultsSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --graphInputPath${graphInputPath} + --outputPath${workingDir}/entities + + + + + + + + yarn + cluster + Merge datasets + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/dataset + --prodInputPath${prodInputGgraphPath}/dataset + --outputPath${graphOutputPath}/dataset + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Dataset + --priority${priority} + + + + + + + + yarn + cluster + Merge otherresearchproducts + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/otherresearchproduct + --prodInputPath${prodInputGgraphPath}/otherresearchproduct + --outputPath${graphOutputPath}/otherresearchproduct + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct + --priority${priority} + + + + + + + + yarn + cluster + Merge softwares + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/software + --prodInputPath${prodInputGgraphPath}/software + --outputPath${graphOutputPath}/software + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Software + --priority${priority} + + + + + + + + yarn + cluster + Merge datasources + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/datasource + --prodInputPath${prodInputGgraphPath}/datasource + --outputPath${graphOutputPath}/datasource + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Datasource + --priority${priority} + + + + + + + + yarn + cluster + Merge organizations + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/organization + --prodInputPath${prodInputGgraphPath}/organization + --outputPath${graphOutputPath}/organization + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Organization + --priority${priority} + + + + + + + + yarn + cluster + Merge projects + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/project + --prodInputPath${prodInputGgraphPath}/project + --outputPath${graphOutputPath}/project + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Project + --priority${priority} + + + + + + + + yarn + cluster + Merge relations + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --betaInputPath${betaInputGgraphPath}/relation + --prodInputPath${prodInputGgraphPath}/relation + --outputPath${graphOutputPath}/relation + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Relation + --priority${priority} + + + + + + + + + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml index 07a125fb6..604f515a5 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml @@ -76,7 +76,7 @@ yarn cluster Merge publications - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -103,7 +103,7 @@ yarn cluster Merge datasets - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -130,7 +130,7 @@ yarn cluster Merge otherresearchproducts - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -157,7 +157,7 @@ yarn cluster Merge softwares - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -184,7 +184,7 @@ yarn cluster Merge datasources - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -211,7 +211,7 @@ yarn cluster Merge organizations - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -238,7 +238,7 @@ yarn cluster Merge projects - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -265,7 +265,7 @@ yarn cluster Merge relations - eu.dnetlib.dhp.oa.graph.merge.MergeGraphSparkJob + eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJobTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJobTest.java similarity index 90% rename from dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJobTest.java rename to dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJobTest.java index 28e8e5abc..0089811cf 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphSparkJobTest.java +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/merge/MergeGraphTableSparkJobTest.java @@ -15,7 +15,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.dnetlib.dhp.schema.oaf.Datasource; -public class MergeGraphSparkJobTest { +public class MergeGraphTableSparkJobTest { private ObjectMapper mapper; @@ -28,7 +28,7 @@ public class MergeGraphSparkJobTest { public void testMergeDatasources() throws IOException { assertEquals( "openaire-cris_1.1", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_cris.json"), d("datasource_UNKNOWN.json")) @@ -36,7 +36,7 @@ public class MergeGraphSparkJobTest { .getClassid()); assertEquals( "openaire-cris_1.1", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_UNKNOWN.json"), d("datasource_cris.json")) @@ -44,7 +44,7 @@ public class MergeGraphSparkJobTest { .getClassid()); assertEquals( "driver-openaire2.0", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_native.json"), d("datasource_driver-openaire2.0.json")) @@ -52,7 +52,7 @@ public class MergeGraphSparkJobTest { .getClassid()); assertEquals( "driver-openaire2.0", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_driver-openaire2.0.json"), d("datasource_native.json")) @@ -60,7 +60,7 @@ public class MergeGraphSparkJobTest { .getClassid()); assertEquals( "openaire4.0", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_notCompatible.json"), d("datasource_openaire4.0.json")) @@ -68,7 +68,7 @@ public class MergeGraphSparkJobTest { .getClassid()); assertEquals( "notCompatible", - MergeGraphSparkJob + MergeGraphTableSparkJob .mergeDatasource( d("datasource_notCompatible.json"), d("datasource_UNKNOWN.json")) diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplicationTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplicationTest.java new file mode 100644 index 000000000..705f1dddb --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplicationTest.java @@ -0,0 +1,99 @@ + +package eu.dnetlib.dhp.oa.graph.raw; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.lenient; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import eu.dnetlib.dhp.oa.graph.clean.CleaningFunctionTest; +import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; +import eu.dnetlib.dhp.schema.common.ModelConstants; +import eu.dnetlib.dhp.schema.oaf.*; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; + +@ExtendWith(MockitoExtension.class) +public class GenerateEntitiesApplicationTest { + + @Mock + private ISLookUpService isLookUpService; + + @Mock + private VocabularyGroup vocs; + + @BeforeEach + public void setUp() throws IOException, ISLookUpException { + + lenient().when(isLookUpService.quickSearchProfile(VocabularyGroup.VOCABULARIES_XQUERY)).thenReturn(vocs()); + lenient() + .when(isLookUpService.quickSearchProfile(VocabularyGroup.VOCABULARY_SYNONYMS_XQUERY)) + .thenReturn(synonyms()); + + vocs = VocabularyGroup.loadVocsFromIS(isLookUpService); + } + + @Test + public void testMergeResult() throws IOException { + Result publication = getResult("oaf_record.xml", Publication.class); + Result dataset = getResult("odf_dataset.xml", Dataset.class); + Result software = getResult("odf_software.xml", Software.class); + Result orp = getResult("oaf_orp.xml", OtherResearchProduct.class); + + verifyMerge(publication, dataset, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + verifyMerge(dataset, publication, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + + verifyMerge(publication, software, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + verifyMerge(software, publication, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + + verifyMerge(publication, orp, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + verifyMerge(orp, publication, Publication.class, ModelConstants.PUBLICATION_RESULTTYPE_CLASSID); + + verifyMerge(dataset, software, Dataset.class, ModelConstants.DATASET_RESULTTYPE_CLASSID); + verifyMerge(software, dataset, Dataset.class, ModelConstants.DATASET_RESULTTYPE_CLASSID); + + verifyMerge(dataset, orp, Dataset.class, ModelConstants.DATASET_RESULTTYPE_CLASSID); + verifyMerge(orp, dataset, Dataset.class, ModelConstants.DATASET_RESULTTYPE_CLASSID); + + verifyMerge(software, orp, Software.class, ModelConstants.SOFTWARE_RESULTTYPE_CLASSID); + verifyMerge(orp, software, Software.class, ModelConstants.SOFTWARE_RESULTTYPE_CLASSID); + } + + protected void verifyMerge(Result publication, Result dataset, Class clazz, + String resultType) { + final Result merge = OafMapperUtils.mergeResults(publication, dataset); + assertTrue(clazz.isAssignableFrom(merge.getClass())); + assertEquals(resultType, merge.getResulttype().getClassid()); + } + + protected Result getResult(String xmlFileName, Class clazz) throws IOException { + final String xml = IOUtils.toString(getClass().getResourceAsStream(xmlFileName)); + return new OdfToOafMapper(vocs, false) + .processMdRecord(xml) + .stream() + .filter(s -> clazz.isAssignableFrom(s.getClass())) + .map(s -> (Result) s) + .findFirst() + .get(); + } + + private List vocs() throws IOException { + return IOUtils + .readLines(CleaningFunctionTest.class.getResourceAsStream("/eu/dnetlib/dhp/oa/graph/clean/terms.txt")); + } + + private List synonyms() throws IOException { + return IOUtils + .readLines(CleaningFunctionTest.class.getResourceAsStream("/eu/dnetlib/dhp/oa/graph/clean/synonyms.txt")); + } + +} From 2bed29eb09616e01ee1d26c082847d7298db9e98 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Fri, 13 Nov 2020 10:05:12 +0100 Subject: [PATCH 03/21] WIP: added oozie workflow for grouping graph entities by id --- .../dhp/schema/oaf/OafMapperUtils.java | 297 +++++++++++++++++- .../dhp/schema/oaf/ResultTypeComparator.java | 49 ++- .../java/eu/dnetlib/dhp/utils/DHPUtils.java | 7 + .../oa/graph/clean/CleanGraphSparkJob.java | 10 +- .../dhp/oa/graph/clean/CleaningFunctions.java | 1 - .../groupbyid/DispatchEntitiesSparkJob.java | 64 ++-- .../GroupEntitiesAndRelationsSparkJob.java | 80 +++-- .../raw/AbstractMdRecordToOafMapper.java | 2 +- .../raw/GenerateEntitiesApplication.java | 24 +- .../raw/MigrateDbEntitiesApplication.java | 10 +- .../dhp/oa/graph/raw/OafToOafMapper.java | 6 +- .../dhp/oa/graph/raw/OdfToOafMapper.java | 6 +- .../dhp/oa/graph/raw/common/Vocabulary.java | 1 + .../oa/graph/raw/common/VocabularyGroup.java | 1 + .../dispatch_entities_bytype_parameters.json | 16 +- .../oa/graph/groupbyid/oozie_app/workflow.xml | 188 ++++++----- .../dhp/oa/graph/merge/oozie_app/workflow.xml | 4 +- .../raw/MigrateDbEntitiesApplicationTest.java | 8 +- .../dhp/oa/provision/XmlConverterJob.java | 15 +- 19 files changed, 578 insertions(+), 211 deletions(-) diff --git a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java index 6ba918069..4a66f91dc 100644 --- a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java +++ b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/OafMapperUtils.java @@ -1,2 +1,297 @@ -package eu.dnetlib.dhp.schema.oaf;public class OafMapperUtils { + +package eu.dnetlib.dhp.schema.oaf; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; + +import eu.dnetlib.dhp.schema.common.ModelSupport; +import eu.dnetlib.dhp.utils.DHPUtils; + +public class OafMapperUtils { + + public static Oaf merge(final Oaf o1, final Oaf o2) { + if (ModelSupport.isSubClass(o1, OafEntity.class)) { + if (ModelSupport.isSubClass(o1, Result.class)) { + + return mergeResults((Result) o1, (Result) o2); + } else if (ModelSupport.isSubClass(o1, Datasource.class)) { + ((Datasource) o1).mergeFrom((Datasource) o2); + } else if (ModelSupport.isSubClass(o1, Organization.class)) { + ((Organization) o1).mergeFrom((Organization) o2); + } else if (ModelSupport.isSubClass(o1, Project.class)) { + ((Project) o1).mergeFrom((Project) o2); + } else { + throw new RuntimeException("invalid OafEntity subtype:" + o1.getClass().getCanonicalName()); + } + } else if (ModelSupport.isSubClass(o1, Relation.class)) { + ((Relation) o1).mergeFrom((Relation) o2); + } else { + throw new RuntimeException("invalid Oaf type:" + o1.getClass().getCanonicalName()); + } + return o1; + } + + public static Result mergeResults(Result r1, Result r2) { + if (new ResultTypeComparator().compare(r1, r2) < 0) { + r1.mergeFrom(r2); + return r1; + } else { + r2.mergeFrom(r1); + return r2; + } + } + + public static KeyValue keyValue(final String k, final String v) { + final KeyValue kv = new KeyValue(); + kv.setKey(k); + kv.setValue(v); + return kv; + } + + public static List listKeyValues(final String... s) { + if (s.length % 2 > 0) { + throw new RuntimeException("Invalid number of parameters (k,v,k,v,....)"); + } + + final List list = new ArrayList<>(); + for (int i = 0; i < s.length; i += 2) { + list.add(keyValue(s[i], s[i + 1])); + } + return list; + } + + public static Field field(final T value, final DataInfo info) { + if (value == null || StringUtils.isBlank(value.toString())) { + return null; + } + + final Field field = new Field<>(); + field.setValue(value); + field.setDataInfo(info); + return field; + } + + public static List> listFields(final DataInfo info, final String... values) { + return Arrays + .stream(values) + .map(v -> field(v, info)) + .filter(Objects::nonNull) + .filter(distinctByKey(f -> f.getValue())) + .collect(Collectors.toList()); + } + + public static List> listFields(final DataInfo info, final List values) { + return values + .stream() + .map(v -> field(v, info)) + .filter(Objects::nonNull) + .filter(distinctByKey(f -> f.getValue())) + .collect(Collectors.toList()); + } + + public static Qualifier unknown(final String schemeid, final String schemename) { + return qualifier("UNKNOWN", "Unknown", schemeid, schemename); + } + + public static Qualifier qualifier( + final String classid, + final String classname, + final String schemeid, + final String schemename) { + final Qualifier q = new Qualifier(); + q.setClassid(classid); + q.setClassname(classname); + q.setSchemeid(schemeid); + q.setSchemename(schemename); + return q; + } + + public static StructuredProperty structuredProperty( + final String value, + final String classid, + final String classname, + final String schemeid, + final String schemename, + final DataInfo dataInfo) { + + return structuredProperty(value, qualifier(classid, classname, schemeid, schemename), dataInfo); + } + + public static StructuredProperty structuredProperty( + final String value, + final Qualifier qualifier, + final DataInfo dataInfo) { + if (value == null) { + return null; + } + final StructuredProperty sp = new StructuredProperty(); + sp.setValue(value); + sp.setQualifier(qualifier); + sp.setDataInfo(dataInfo); + return sp; + } + + public static ExtraInfo extraInfo( + final String name, + final String value, + final String typology, + final String provenance, + final String trust) { + final ExtraInfo info = new ExtraInfo(); + info.setName(name); + info.setValue(value); + info.setTypology(typology); + info.setProvenance(provenance); + info.setTrust(trust); + return info; + } + + public static OAIProvenance oaiIProvenance( + final String identifier, + final String baseURL, + final String metadataNamespace, + final Boolean altered, + final String datestamp, + final String harvestDate) { + + final OriginDescription desc = new OriginDescription(); + desc.setIdentifier(identifier); + desc.setBaseURL(baseURL); + desc.setMetadataNamespace(metadataNamespace); + desc.setAltered(altered); + desc.setDatestamp(datestamp); + desc.setHarvestDate(harvestDate); + + final OAIProvenance p = new OAIProvenance(); + p.setOriginDescription(desc); + + return p; + } + + public static Journal journal( + final String name, + final String issnPrinted, + final String issnOnline, + final String issnLinking, + final DataInfo dataInfo) { + return journal( + name, + issnPrinted, + issnOnline, + issnLinking, + null, + null, + null, + null, + null, + null, + null, + dataInfo); + } + + public static Journal journal( + final String name, + final String issnPrinted, + final String issnOnline, + final String issnLinking, + final String ep, + final String iss, + final String sp, + final String vol, + final String edition, + final String conferenceplace, + final String conferencedate, + final DataInfo dataInfo) { + + if (StringUtils.isNotBlank(name) + || StringUtils.isNotBlank(issnPrinted) + || StringUtils.isNotBlank(issnOnline) + || StringUtils.isNotBlank(issnLinking)) { + final Journal j = new Journal(); + j.setName(name); + j.setIssnPrinted(issnPrinted); + j.setIssnOnline(issnOnline); + j.setIssnLinking(issnLinking); + j.setEp(ep); + j.setIss(iss); + j.setSp(sp); + j.setVol(vol); + j.setEdition(edition); + j.setConferenceplace(conferenceplace); + j.setConferencedate(conferencedate); + j.setDataInfo(dataInfo); + return j; + } else { + return null; + } + } + + public static DataInfo dataInfo( + final Boolean deletedbyinference, + final String inferenceprovenance, + final Boolean inferred, + final Boolean invisible, + final Qualifier provenanceaction, + final String trust) { + final DataInfo d = new DataInfo(); + d.setDeletedbyinference(deletedbyinference); + d.setInferenceprovenance(inferenceprovenance); + d.setInferred(inferred); + d.setInvisible(invisible); + d.setProvenanceaction(provenanceaction); + d.setTrust(trust); + return d; + } + + public static String createOpenaireId( + final int prefix, + final String originalId, + final boolean to_md5) { + if (StringUtils.isBlank(originalId)) { + return null; + } else if (to_md5) { + final String nsPrefix = StringUtils.substringBefore(originalId, "::"); + final String rest = StringUtils.substringAfter(originalId, "::"); + return String.format("%s|%s::%s", prefix, nsPrefix, DHPUtils.md5(rest)); + } else { + return String.format("%s|%s", prefix, originalId); + } + } + + public static String createOpenaireId( + final String type, + final String originalId, + final boolean to_md5) { + switch (type) { + case "datasource": + return createOpenaireId(10, originalId, to_md5); + case "organization": + return createOpenaireId(20, originalId, to_md5); + case "person": + return createOpenaireId(30, originalId, to_md5); + case "project": + return createOpenaireId(40, originalId, to_md5); + default: + return createOpenaireId(50, originalId, to_md5); + } + } + + public static String asString(final Object o) { + return o == null ? "" : o.toString(); + } + + public static Predicate distinctByKey( + final Function keyExtractor) { + final Map seen = new ConcurrentHashMap<>(); + return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; + } } diff --git a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java index a2e64b83b..6c11d1a85 100644 --- a/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java +++ b/dhp-common/src/main/java/eu/dnetlib/dhp/schema/oaf/ResultTypeComparator.java @@ -1,2 +1,49 @@ -package eu.dnetlib.dhp.schema.oaf;public class ResultTypeComparator { + +package eu.dnetlib.dhp.schema.oaf; + +import java.util.Comparator; + +import eu.dnetlib.dhp.schema.common.ModelConstants; + +public class ResultTypeComparator implements Comparator { + + @Override + public int compare(Result left, Result right) { + + if (left == null && right == null) + return 0; + if (left == null) + return 1; + if (right == null) + return -1; + + String lClass = left.getResulttype().getClassid(); + String rClass = right.getResulttype().getClassid(); + + if (lClass.equals(rClass)) + return 0; + + if (lClass.equals(ModelConstants.PUBLICATION_RESULTTYPE_CLASSID)) + return -1; + if (rClass.equals(ModelConstants.PUBLICATION_RESULTTYPE_CLASSID)) + return 1; + + if (lClass.equals(ModelConstants.DATASET_RESULTTYPE_CLASSID)) + return -1; + if (rClass.equals(ModelConstants.DATASET_RESULTTYPE_CLASSID)) + return 1; + + if (lClass.equals(ModelConstants.SOFTWARE_RESULTTYPE_CLASSID)) + return -1; + if (rClass.equals(ModelConstants.SOFTWARE_RESULTTYPE_CLASSID)) + return 1; + + if (lClass.equals(ModelConstants.ORP_RESULTTYPE_CLASSID)) + return -1; + if (rClass.equals(ModelConstants.ORP_RESULTTYPE_CLASSID)) + return 1; + + // Else (but unlikely), lexicographical ordering will do. + return lClass.compareTo(rClass); + } } diff --git a/dhp-common/src/main/java/eu/dnetlib/dhp/utils/DHPUtils.java b/dhp-common/src/main/java/eu/dnetlib/dhp/utils/DHPUtils.java index dfbaf3a6c..8872174a5 100644 --- a/dhp-common/src/main/java/eu/dnetlib/dhp/utils/DHPUtils.java +++ b/dhp-common/src/main/java/eu/dnetlib/dhp/utils/DHPUtils.java @@ -5,6 +5,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -15,9 +16,15 @@ import org.apache.commons.codec.binary.Hex; import com.jayway.jsonpath.JsonPath; import net.minidev.json.JSONArray; +import scala.collection.JavaConverters; +import scala.collection.Seq; public class DHPUtils { + public static Seq toSeq(List list) { + return JavaConverters.asScalaIteratorConverter(list.iterator()).asScala().toSeq(); + } + public static String md5(final String s) { try { final MessageDigest md = MessageDigest.getInstance("MD5"); diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java index e295b9503..714b35dac 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java @@ -3,13 +3,9 @@ package eu.dnetlib.dhp.oa.graph.clean; import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; -import java.io.BufferedInputStream; -import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.spark.SparkConf; import org.apache.spark.api.java.function.MapFunction; import org.apache.spark.sql.Dataset; @@ -23,11 +19,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.dnetlib.dhp.application.ArgumentApplicationParser; import eu.dnetlib.dhp.common.HdfsSupport; -import eu.dnetlib.dhp.oa.graph.raw.AbstractMdRecordToOafMapper; -import eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils; import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; -import eu.dnetlib.dhp.schema.common.ModelConstants; -import eu.dnetlib.dhp.schema.oaf.*; +import eu.dnetlib.dhp.schema.oaf.Oaf; +import eu.dnetlib.dhp.schema.oaf.OafEntity; import eu.dnetlib.dhp.utils.ISLookupClientFactory; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java index 56a4aaf5a..9f06ea056 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java @@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils; import com.clearspring.analytics.util.Lists; import eu.dnetlib.dhp.oa.graph.raw.AbstractMdRecordToOafMapper; -import eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils; import eu.dnetlib.dhp.schema.common.ModelConstants; import eu.dnetlib.dhp.schema.oaf.*; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java index 6b90e9971..1b4226411 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java @@ -1,11 +1,10 @@ -package eu.dnetlib.dhp.oa.graph.fuse; +package eu.dnetlib.dhp.oa.graph.groupbyid; + +import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; + +import java.util.Optional; -import eu.dnetlib.dhp.application.ArgumentApplicationParser; -import eu.dnetlib.dhp.common.HdfsSupport; -import eu.dnetlib.dhp.oa.graph.raw.MigrateMongoMdstoresApplication; -import eu.dnetlib.dhp.schema.common.ModelSupport; -import eu.dnetlib.dhp.schema.oaf.Oaf; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.spark.SparkConf; @@ -17,14 +16,22 @@ import org.apache.spark.sql.SparkSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Optional; +import com.fasterxml.jackson.databind.ObjectMapper; -import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; +import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.common.HdfsSupport; +import eu.dnetlib.dhp.oa.graph.raw.MigrateMongoMdstoresApplication; +import eu.dnetlib.dhp.schema.common.ModelSupport; +import eu.dnetlib.dhp.schema.oaf.Oaf; +import eu.dnetlib.dhp.schema.oaf.OafEntity; +import scala.Tuple2; public class DispatchEntitiesSparkJob { private static final Logger log = LoggerFactory.getLogger(DispatchEntitiesSparkJob.class); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + public static void main(final String[] args) throws Exception { final ArgumentApplicationParser parser = new ArgumentApplicationParser( IOUtils @@ -40,48 +47,51 @@ public class DispatchEntitiesSparkJob { .orElse(Boolean.TRUE); log.info("isSparkSessionManaged: {}", isSparkSessionManaged); - final String sourcePath = parser.get("sourcePath"); - final String targetPath = parser.get("graphRawPath"); + final String entitiesPath = parser.get("entitiesPath"); + log.info("entitiesPath: {}", entitiesPath); + + final String outputPath = parser.get("outputPath"); + log.info("outputPath: {}", outputPath); + + String graphTableClassName = parser.get("graphTableClassName"); + log.info("graphTableClassName: {}", graphTableClassName); + + Class entityClazz = (Class) Class.forName(graphTableClassName); SparkConf conf = new SparkConf(); + conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); + conf.registerKryoClasses(ModelSupport.getOafModelClasses()); + runWithSparkSession( conf, isSparkSessionManaged, spark -> { - removeOutputDir(spark, targetPath); - ModelSupport.oafTypes - .values() - .forEach(clazz -> processEntity(spark, clazz, sourcePath, targetPath)); + HdfsSupport.remove(outputPath, spark.sparkContext().hadoopConfiguration()); + dispatchOaf(spark, entityClazz, entitiesPath, outputPath); }); } - private static void processEntity( + private static void dispatchOaf( final SparkSession spark, final Class clazz, final String sourcePath, final String targetPath) { - final String type = clazz.getSimpleName().toLowerCase(); - log.info("Processing entities ({}) in file: {}", type, sourcePath); + log.info("Processing entities ({}) in file: {}", clazz.getName(), sourcePath); spark .read() .textFile(sourcePath) - .filter((FilterFunction) value -> isEntityType(value, type)) - .map( - (MapFunction) l -> StringUtils.substringAfter(l, "|"), - Encoders.STRING()) + .filter((FilterFunction) s -> isEntityType(s, clazz)) + .map((MapFunction) s -> StringUtils.substringAfter(s, "|"), Encoders.STRING()) .write() .option("compression", "gzip") .mode(SaveMode.Overwrite) - .text(targetPath + "/" + type); + .text(targetPath); } - private static boolean isEntityType(final String line, final String type) { - return StringUtils.substringBefore(line, "|").equalsIgnoreCase(type); + private static boolean isEntityType(final String s, final Class clazz) { + return StringUtils.substringBefore(s, "|").equals(clazz.getName()); } - private static void removeOutputDir(SparkSession spark, String path) { - HdfsSupport.remove(path, spark.sparkContext().hadoopConfiguration()); - } } diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java index 7ab8646ec..1d887cecb 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java @@ -12,9 +12,9 @@ import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.hadoop.io.compress.GzipCodec; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.FilterFunction; import org.apache.spark.api.java.function.MapFunction; import org.apache.spark.sql.*; import org.apache.spark.sql.expressions.Aggregator; @@ -22,7 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.Option; import eu.dnetlib.dhp.application.ArgumentApplicationParser; import eu.dnetlib.dhp.common.HdfsSupport; @@ -33,19 +36,21 @@ import scala.Tuple2; /** * Groups the graph content by entity identifier to ensure ID uniqueness */ -public class GroupEntitiesSparkJob { +public class GroupEntitiesAndRelationsSparkJob { - private static final Logger log = LoggerFactory.getLogger(GroupEntitiesSparkJob.class); + private static final Logger log = LoggerFactory.getLogger(GroupEntitiesAndRelationsSparkJob.class); private final static String ID_JPATH = "$.id"; + private final static String SOURCE_JPATH = "$.source"; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static void main(String[] args) throws Exception { String jsonConfiguration = IOUtils .toString( - GroupEntitiesSparkJob.class + GroupEntitiesAndRelationsSparkJob.class .getResourceAsStream( "/eu/dnetlib/dhp/oa/graph/group_graph_entities_parameters.json")); final ArgumentApplicationParser parser = new ArgumentApplicationParser(jsonConfiguration); @@ -72,11 +77,11 @@ public class GroupEntitiesSparkJob { isSparkSessionManaged, spark -> { HdfsSupport.remove(outputPath, spark.sparkContext().hadoopConfiguration()); - groupEntities(spark, graphInputPath, outputPath); + groupEntitiesAndRelations(spark, graphInputPath, outputPath); }); } - private static void groupEntities( + private static void groupEntitiesAndRelations( SparkSession spark, String inputPath, String outputPath) { @@ -85,14 +90,19 @@ public class GroupEntitiesSparkJob { final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); spark .read() - .textFile(toSeq(listEntityPaths(inputPath, sc))) - .map((MapFunction) s -> parseEntity(s), Encoders.kryo(Oaf.class)) + .textFile(toSeq(listPaths(inputPath, sc))) + .map((MapFunction) s -> parseOaf(s), Encoders.kryo(Oaf.class)) + .filter((FilterFunction) oaf -> StringUtils.isNotBlank(ModelSupport.idFn().apply(oaf))) .groupByKey((MapFunction) oaf -> ModelSupport.idFn().apply(oaf), Encoders.STRING()) .agg(aggregator) - .map((MapFunction, Oaf>) Tuple2::_2, Encoders.kryo(Oaf.class)) + .map( + (MapFunction, String>) t -> t._2().getClass().getName() + + "|" + OBJECT_MAPPER.writeValueAsString(t._2()), + Encoders.STRING()) .write() + .option("compression", "gzip") .mode(SaveMode.Overwrite) - .save(outputPath); + .text(outputPath); } public static class GroupingAggregator extends Aggregator { @@ -136,51 +146,61 @@ public class GroupEntitiesSparkJob { } - private static Oaf parseEntity(String s) { - String prefix = StringUtils.substringBefore(jPath(ID_JPATH, s), "|"); - try { + private static Oaf parseOaf(String s) { + + DocumentContext dc = JsonPath + .parse(s, Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS)); + final String id = dc.read(ID_JPATH); + if (StringUtils.isNotBlank(id)) { + + String prefix = StringUtils.substringBefore(id, "|"); switch (prefix) { case "10": - return OBJECT_MAPPER.readValue(s, Datasource.class); + return parse(s, Datasource.class); case "20": - return OBJECT_MAPPER.readValue(s, Organization.class); + return parse(s, Organization.class); case "40": - return OBJECT_MAPPER.readValue(s, Project.class); + return parse(s, Project.class); case "50": - String resultType = jPath("$.resulttype.classid", s); + String resultType = dc.read("$.resulttype.classid"); switch (resultType) { case "publication": - return OBJECT_MAPPER.readValue(s, Publication.class); + return parse(s, Publication.class); case "dataset": - return OBJECT_MAPPER.readValue(s, eu.dnetlib.dhp.schema.oaf.Dataset.class); + return parse(s, eu.dnetlib.dhp.schema.oaf.Dataset.class); case "software": - return OBJECT_MAPPER.readValue(s, Software.class); + return parse(s, Software.class); case "other": - return OBJECT_MAPPER.readValue(s, OtherResearchProduct.class); + return parse(s, OtherResearchProduct.class); default: throw new IllegalArgumentException(String.format("invalid resultType: '%s'", resultType)); } default: throw new IllegalArgumentException(String.format("invalid id prefix: '%s'", prefix)); } + } else { + String source = dc.read(SOURCE_JPATH); + if (StringUtils.isNotBlank(source)) { + return parse(s, Relation.class); + } else { + throw new IllegalArgumentException(String.format("invalid oaf: '%s'", s)); + } + } + } + + private static Oaf parse(String s, Class clazz) { + try { + return OBJECT_MAPPER.readValue(s, clazz); } catch (IOException e) { throw new RuntimeException(e); } } - private static List listEntityPaths(String inputPath, JavaSparkContext sc) { + private static List listPaths(String inputPath, JavaSparkContext sc) { return HdfsSupport .listFiles(inputPath, sc.hadoopConfiguration()) .stream() - .filter(p -> !p.contains("relation")) .collect(Collectors.toList()); } - private static String jPath(final String path, final String json) { - Object o = JsonPath.read(json, path); - if (o instanceof String) - return (String) o; - throw new IllegalStateException(String.format("could not extract '%s' from:\n%s", path, json)); - } - } diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java index 5b6ae72f1..da4b5e324 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java @@ -1,8 +1,8 @@ package eu.dnetlib.dhp.oa.graph.raw; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.*; import static eu.dnetlib.dhp.schema.common.ModelConstants.*; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.*; import java.util.*; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java index 99aa9c3f0..cfd190670 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/GenerateEntitiesApplication.java @@ -4,9 +4,11 @@ package eu.dnetlib.dhp.oa.graph.raw; import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -18,7 +20,6 @@ import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.sql.SparkSession; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,7 +69,7 @@ public class GenerateEntitiesApplication { final SparkConf conf = new SparkConf(); runWithSparkSession(conf, isSparkSessionManaged, spark -> { - removeOutputDir(spark, targetPath); + HdfsSupport.remove(targetPath, spark.sparkContext().hadoopConfiguration()); generateEntities(spark, vocs, sourcePaths, targetPath); }); } @@ -82,7 +83,7 @@ public class GenerateEntitiesApplication { final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); final List existingSourcePaths = Arrays .stream(sourcePaths.split(",")) - .filter(p -> exists(sc, p)) + .filter(p -> HdfsSupport.exists(p, sc.hadoopConfiguration())) .collect(Collectors.toList()); log.info("Generate entities from files:"); @@ -160,17 +161,4 @@ public class GenerateEntitiesApplication { } } - private static boolean exists(final JavaSparkContext context, final String pathToFile) { - try { - final FileSystem hdfs = FileSystem.get(context.hadoopConfiguration()); - final Path path = new Path(pathToFile); - return hdfs.exists(path); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - - private static void removeOutputDir(final SparkSession spark, final String path) { - HdfsSupport.remove(path, spark.sparkContext().hadoopConfiguration()); - } } diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java index 6365a1db9..f6f0e0a36 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplication.java @@ -1,15 +1,6 @@ package eu.dnetlib.dhp.oa.graph.raw; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.asString; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.createOpenaireId; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.dataInfo; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.field; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.journal; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.listFields; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.listKeyValues; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.qualifier; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.structuredProperty; import static eu.dnetlib.dhp.schema.common.ModelConstants.DATASET_DEFAULT_RESULTTYPE; import static eu.dnetlib.dhp.schema.common.ModelConstants.DATASOURCE_ORGANIZATION; import static eu.dnetlib.dhp.schema.common.ModelConstants.DNET_PROVENANCE_ACTIONS; @@ -32,6 +23,7 @@ import static eu.dnetlib.dhp.schema.common.ModelConstants.RESULT_PROJECT; import static eu.dnetlib.dhp.schema.common.ModelConstants.RESULT_RESULT; import static eu.dnetlib.dhp.schema.common.ModelConstants.SOFTWARE_DEFAULT_RESULTTYPE; import static eu.dnetlib.dhp.schema.common.ModelConstants.USER_CLAIM; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.*; import java.io.Closeable; import java.io.IOException; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OafToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OafToOafMapper.java index dea80fabd..e62bc0790 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OafToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OafToOafMapper.java @@ -1,10 +1,10 @@ package eu.dnetlib.dhp.oa.graph.raw; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.createOpenaireId; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.field; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.structuredProperty; import static eu.dnetlib.dhp.schema.common.ModelConstants.*; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.createOpenaireId; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.field; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.structuredProperty; import java.util.ArrayList; import java.util.List; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java index 6fe7bb971..7124684d5 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java @@ -1,10 +1,10 @@ package eu.dnetlib.dhp.oa.graph.raw; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.createOpenaireId; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.field; -import static eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils.structuredProperty; import static eu.dnetlib.dhp.schema.common.ModelConstants.*; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.createOpenaireId; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.field; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.structuredProperty; import java.util.ArrayList; import java.util.Arrays; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/Vocabulary.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/Vocabulary.java index 9bf198c8b..bfc4fd6f1 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/Vocabulary.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/Vocabulary.java @@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Maps; +import eu.dnetlib.dhp.schema.oaf.OafMapperUtils; import eu.dnetlib.dhp.schema.oaf.Qualifier; public class Vocabulary implements Serializable { diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/VocabularyGroup.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/VocabularyGroup.java index 334339d3b..32452bdc5 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/VocabularyGroup.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/common/VocabularyGroup.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import eu.dnetlib.dhp.schema.oaf.OafMapperUtils; import eu.dnetlib.dhp.schema.oaf.Qualifier; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json index 7d995f39a..a75ff3653 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json @@ -6,15 +6,21 @@ "paramRequired": false }, { - "paramName": "s", - "paramLongName": "sourcePath", - "paramDescription": "the source path", + "paramName": "ep", + "paramLongName": "entitiesPath", + "paramDescription": "the entities path", "paramRequired": true }, { "paramName": "g", - "paramLongName": "graphRawPath", - "paramDescription": "the path of the graph Raw in hdfs", + "paramLongName": "outputPath", + "paramDescription": "the output path to store the dispatched entities", + "paramRequired": true + }, + { + "paramName": "class", + "paramLongName": "graphTableClassName", + "paramDescription": "class name modelling the graph table", "paramRequired": true } ] \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml index 3715d097d..70b2ea68e 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml @@ -1,4 +1,4 @@ - + @@ -46,18 +46,18 @@ - + Action failed, error message[${wf:errorMessage(wf:lastErrorNode())}] - + yarn cluster - Fuse graph entities by ID - eu.dnetlib.dhp.oa.graph.fuse.FuseGraphResultsSparkJob + group graph entities and relations + eu.dnetlib.dhp.oa.graph.groupbyid.GroupEntitiesAndRelationsSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -70,18 +70,29 @@ --conf spark.sql.shuffle.partitions=7680 --graphInputPath${graphInputPath} - --outputPath${workingDir}/entities + --outputPath${workingDir}/grouped_entities - + - + + + + + + + + + + + + yarn cluster - Merge datasets - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch publications + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -93,22 +104,45 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/dataset - --prodInputPath${prodInputGgraphPath}/dataset - --outputPath${graphOutputPath}/dataset + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/publication + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Publication + + + + + + + + yarn + cluster + Dispatch datasets + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/dataset --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Dataset - --priority${priority} - + - + yarn cluster - Merge otherresearchproducts - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch softwares + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -120,49 +154,20 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/otherresearchproduct - --prodInputPath${prodInputGgraphPath}/otherresearchproduct - --outputPath${graphOutputPath}/otherresearchproduct - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct - --priority${priority} - - - - - - - - yarn - cluster - Merge softwares - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --betaInputPath${betaInputGgraphPath}/software - --prodInputPath${prodInputGgraphPath}/software - --outputPath${graphOutputPath}/software + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/software --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Software - --priority${priority} - + - + yarn cluster - Merge datasources - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch otherresearchproducts + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -174,22 +179,45 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/datasource - --prodInputPath${prodInputGgraphPath}/datasource - --outputPath${graphOutputPath}/datasource + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/otherresearchproduct + --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct + + + + + + + + yarn + cluster + Dispatch datasources + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/datasource --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Datasource - --priority${priority} - + - + yarn cluster - Merge organizations - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch organizations + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -201,22 +229,20 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/organization - --prodInputPath${prodInputGgraphPath}/organization - --outputPath${graphOutputPath}/organization + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/organization --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Organization - --priority${priority} - + - + yarn cluster - Merge projects - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch project + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -228,22 +254,20 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/project - --prodInputPath${prodInputGgraphPath}/project - --outputPath${graphOutputPath}/project + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/project --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Project - --priority${priority} - + - + yarn cluster - Merge relations - eu.dnetlib.dhp.oa.graph.merge.MergeGraphTableSparkJob + Dispatch relations + eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob dhp-graph-mapper-${projectVersion}.jar --executor-cores=${sparkExecutorCores} @@ -255,17 +279,15 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/relation - --prodInputPath${prodInputGgraphPath}/relation - --outputPath${graphOutputPath}/relation + --entitiesPath${workingDir}/grouped_entities + --outputPath${outputPath}/relation --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Relation - --priority${priority} - + - + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml index 604f515a5..5af117d68 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml @@ -2,11 +2,11 @@ - betaInputGgraphPath + betaInputGraphPath the beta graph root path - prodInputGgraphPath + prodInputGraphPath the production graph root path diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplicationTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplicationTest.java index f663d6095..9cf75f208 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplicationTest.java +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MigrateDbEntitiesApplicationTest.java @@ -27,14 +27,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import eu.dnetlib.dhp.oa.graph.raw.common.OafMapperUtils; import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; -import eu.dnetlib.dhp.schema.oaf.Datasource; -import eu.dnetlib.dhp.schema.oaf.Oaf; -import eu.dnetlib.dhp.schema.oaf.Organization; -import eu.dnetlib.dhp.schema.oaf.Project; -import eu.dnetlib.dhp.schema.oaf.Relation; -import eu.dnetlib.dhp.schema.oaf.Result; +import eu.dnetlib.dhp.schema.oaf.*; @ExtendWith(MockitoExtension.class) public class MigrateDbEntitiesApplicationTest { diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlConverterJob.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlConverterJob.java index d8eba31b6..b44ed7446 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlConverterJob.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlConverterJob.java @@ -2,12 +2,11 @@ package eu.dnetlib.dhp.oa.provision; import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; +import static eu.dnetlib.dhp.utils.DHPUtils.toSeq; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; import org.apache.hadoop.io.Text; @@ -28,13 +27,11 @@ import com.google.common.collect.Maps; import eu.dnetlib.dhp.application.ArgumentApplicationParser; import eu.dnetlib.dhp.common.HdfsSupport; -import eu.dnetlib.dhp.oa.provision.model.*; +import eu.dnetlib.dhp.oa.provision.model.JoinedEntity; +import eu.dnetlib.dhp.oa.provision.model.ProvisionModelSupport; import eu.dnetlib.dhp.oa.provision.utils.ContextMapper; import eu.dnetlib.dhp.oa.provision.utils.XmlRecordFactory; -import eu.dnetlib.dhp.schema.oaf.*; import scala.Tuple2; -import scala.collection.JavaConverters; -import scala.collection.Seq; /** * XmlConverterJob converts the JoinedEntities as XML records @@ -43,8 +40,6 @@ public class XmlConverterJob { private static final Logger log = LoggerFactory.getLogger(XmlConverterJob.class); - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - public static final String schemaLocation = "https://www.openaire.eu/schema/1.0/oaf-1.0.xsd"; public static void main(String[] args) throws Exception { @@ -129,10 +124,6 @@ public class XmlConverterJob { HdfsSupport.remove(path, spark.sparkContext().hadoopConfiguration()); } - private static Seq toSeq(List list) { - return JavaConverters.asScalaIteratorConverter(list.iterator()).asScala().toSeq(); - } - private static Map prepareAccumulators(SparkContext sc) { Map accumulators = Maps.newHashMap(); accumulators From 528231a287be05c251709773c62ed8386382e8a9 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Fri, 13 Nov 2020 15:37:48 +0100 Subject: [PATCH 04/21] grouping graph entities by id turned out to be an easy extension for the already existing cleaning workflow --- .../oa/graph/clean/CleanGraphSparkJob.java | 14 +- .../GroupEntitiesAndRelationsSparkJob.java | 2 +- .../groupbyid/DispatchEntitiesSparkJob.java | 97 ------ .../dhp/oa/graph/clean/oozie_app/workflow.xml | 26 +- .../groupbyid/oozie_app/config-default.xml | 18 -- .../oa/graph/groupbyid/oozie_app/workflow.xml | 293 ------------------ 6 files changed, 35 insertions(+), 415 deletions(-) rename dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/{groupbyid => clean}/GroupEntitiesAndRelationsSparkJob.java (99%) delete mode 100644 dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java delete mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml delete mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java index 714b35dac..8231dd77e 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleanGraphSparkJob.java @@ -6,7 +6,9 @@ import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; import java.util.Optional; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.spark.SparkConf; +import org.apache.spark.api.java.function.FilterFunction; import org.apache.spark.api.java.function.MapFunction; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Encoders; @@ -69,12 +71,12 @@ public class CleanGraphSparkJob { conf, isSparkSessionManaged, spark -> { - removeOutputDir(spark, outputPath); - fixGraphTable(spark, vocs, inputPath, entityClazz, outputPath); + HdfsSupport.remove(outputPath, spark.sparkContext().hadoopConfiguration()); + cleanGraphTable(spark, vocs, inputPath, entityClazz, outputPath); }); } - private static void fixGraphTable( + private static void cleanGraphTable( SparkSession spark, VocabularyGroup vocs, String inputPath, @@ -100,13 +102,15 @@ public class CleanGraphSparkJob { return spark .read() .textFile(inputEntityPath) + .filter((FilterFunction) s -> isEntityType(s, clazz)) + .map((MapFunction) s -> StringUtils.substringAfter(s, "|"), Encoders.STRING()) .map( (MapFunction) value -> OBJECT_MAPPER.readValue(value, clazz), Encoders.bean(clazz)); } - private static void removeOutputDir(SparkSession spark, String path) { - HdfsSupport.remove(path, spark.sparkContext().hadoopConfiguration()); + private static boolean isEntityType(final String s, final Class clazz) { + return StringUtils.substringBefore(s, "|").equals(clazz.getName()); } } diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/GroupEntitiesAndRelationsSparkJob.java similarity index 99% rename from dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java rename to dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/GroupEntitiesAndRelationsSparkJob.java index 1d887cecb..9c80528e3 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/GroupEntitiesAndRelationsSparkJob.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/GroupEntitiesAndRelationsSparkJob.java @@ -1,5 +1,5 @@ -package eu.dnetlib.dhp.oa.graph.groupbyid; +package eu.dnetlib.dhp.oa.graph.clean; import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; import static eu.dnetlib.dhp.utils.DHPUtils.toSeq; diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java deleted file mode 100644 index 1b4226411..000000000 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/groupbyid/DispatchEntitiesSparkJob.java +++ /dev/null @@ -1,97 +0,0 @@ - -package eu.dnetlib.dhp.oa.graph.groupbyid; - -import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; - -import java.util.Optional; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.spark.SparkConf; -import org.apache.spark.api.java.function.FilterFunction; -import org.apache.spark.api.java.function.MapFunction; -import org.apache.spark.sql.Encoders; -import org.apache.spark.sql.SaveMode; -import org.apache.spark.sql.SparkSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import eu.dnetlib.dhp.application.ArgumentApplicationParser; -import eu.dnetlib.dhp.common.HdfsSupport; -import eu.dnetlib.dhp.oa.graph.raw.MigrateMongoMdstoresApplication; -import eu.dnetlib.dhp.schema.common.ModelSupport; -import eu.dnetlib.dhp.schema.oaf.Oaf; -import eu.dnetlib.dhp.schema.oaf.OafEntity; -import scala.Tuple2; - -public class DispatchEntitiesSparkJob { - - private static final Logger log = LoggerFactory.getLogger(DispatchEntitiesSparkJob.class); - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - public static void main(final String[] args) throws Exception { - final ArgumentApplicationParser parser = new ArgumentApplicationParser( - IOUtils - .toString( - MigrateMongoMdstoresApplication.class - .getResourceAsStream( - "/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json"))); - parser.parseArgument(args); - - Boolean isSparkSessionManaged = Optional - .ofNullable(parser.get("isSparkSessionManaged")) - .map(Boolean::valueOf) - .orElse(Boolean.TRUE); - log.info("isSparkSessionManaged: {}", isSparkSessionManaged); - - final String entitiesPath = parser.get("entitiesPath"); - log.info("entitiesPath: {}", entitiesPath); - - final String outputPath = parser.get("outputPath"); - log.info("outputPath: {}", outputPath); - - String graphTableClassName = parser.get("graphTableClassName"); - log.info("graphTableClassName: {}", graphTableClassName); - - Class entityClazz = (Class) Class.forName(graphTableClassName); - - SparkConf conf = new SparkConf(); - conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); - conf.registerKryoClasses(ModelSupport.getOafModelClasses()); - - runWithSparkSession( - conf, - isSparkSessionManaged, - spark -> { - HdfsSupport.remove(outputPath, spark.sparkContext().hadoopConfiguration()); - dispatchOaf(spark, entityClazz, entitiesPath, outputPath); - }); - } - - private static void dispatchOaf( - final SparkSession spark, - final Class clazz, - final String sourcePath, - final String targetPath) { - - log.info("Processing entities ({}) in file: {}", clazz.getName(), sourcePath); - - spark - .read() - .textFile(sourcePath) - .filter((FilterFunction) s -> isEntityType(s, clazz)) - .map((MapFunction) s -> StringUtils.substringAfter(s, "|"), Encoders.STRING()) - .write() - .option("compression", "gzip") - .mode(SaveMode.Overwrite) - .text(targetPath); - } - - private static boolean isEntityType(final String s, final Class clazz) { - return StringUtils.substringBefore(s, "|").equals(clazz.getName()); - } - -} diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml index 7329df29a..8b6ca9de6 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml @@ -50,12 +50,36 @@ - + Action failed, error message[${wf:errorMessage(wf:lastErrorNode())}] + + + yarn + cluster + group graph entities and relations + eu.dnetlib.dhp.oa.graph.clean.GroupEntitiesAndRelationsSparkJob + dhp-graph-mapper-${projectVersion}.jar + + --executor-cores=${sparkExecutorCores} + --executor-memory=${sparkExecutorMemory} + --driver-memory=${sparkDriverMemory} + --conf spark.extraListeners=${spark2ExtraListeners} + --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} + --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} + --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} + --conf spark.sql.shuffle.partitions=7680 + + --graphInputPath${graphInputPath} + --outputPath${workingDir}/grouped_entities + + + + + diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml deleted file mode 100644 index 2e0ed9aee..000000000 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/config-default.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - jobTracker - yarnRM - - - nameNode - hdfs://nameservice1 - - - oozie.use.system.libpath - true - - - oozie.action.sharelib.for.spark - spark2 - - \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml deleted file mode 100644 index 70b2ea68e..000000000 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/groupbyid/oozie_app/workflow.xml +++ /dev/null @@ -1,293 +0,0 @@ - - - - - graphInputPath - the graph root input path - - - outputPath - the graph root output path - - - - sparkDriverMemory - memory for driver process - - - sparkExecutorMemory - memory for individual executor - - - sparkExecutorCores - number of cores used by single executor - - - oozieActionShareLibForSpark2 - oozie action sharelib for spark 2.* - - - spark2ExtraListeners - com.cloudera.spark.lineage.NavigatorAppListener - spark 2.* extra listeners classname - - - spark2SqlQueryExecutionListeners - com.cloudera.spark.lineage.NavigatorQueryListener - spark 2.* sql query execution listeners classname - - - spark2YarnHistoryServerAddress - spark 2.* yarn history server address - - - spark2EventLogDir - spark 2.* event log dir location - - - - - - - Action failed, error message[${wf:errorMessage(wf:lastErrorNode())}] - - - - - yarn - cluster - group graph entities and relations - eu.dnetlib.dhp.oa.graph.groupbyid.GroupEntitiesAndRelationsSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --graphInputPath${graphInputPath} - --outputPath${workingDir}/grouped_entities - - - - - - - - - - - - - - - - - - - yarn - cluster - Dispatch publications - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/publication - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Publication - - - - - - - - yarn - cluster - Dispatch datasets - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/dataset - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Dataset - - - - - - - - yarn - cluster - Dispatch softwares - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/software - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Software - - - - - - - - yarn - cluster - Dispatch otherresearchproducts - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/otherresearchproduct - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct - - - - - - - - yarn - cluster - Dispatch datasources - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/datasource - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Datasource - - - - - - - - yarn - cluster - Dispatch organizations - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/organization - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Organization - - - - - - - - yarn - cluster - Dispatch project - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/project - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Project - - - - - - - - yarn - cluster - Dispatch relations - eu.dnetlib.dhp.oa.graph.groupbyid.DispatchEntitiesSparkJob - dhp-graph-mapper-${projectVersion}.jar - - --executor-cores=${sparkExecutorCores} - --executor-memory=${sparkExecutorMemory} - --driver-memory=${sparkDriverMemory} - --conf spark.extraListeners=${spark2ExtraListeners} - --conf spark.sql.queryExecutionListeners=${spark2SqlQueryExecutionListeners} - --conf spark.yarn.historyServer.address=${spark2YarnHistoryServerAddress} - --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} - --conf spark.sql.shuffle.partitions=7680 - - --entitiesPath${workingDir}/grouped_entities - --outputPath${outputPath}/relation - --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Relation - - - - - - - - - \ No newline at end of file From 2facfefc190b47496fbc2806c3ff9cacf365d3af Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Fri, 13 Nov 2020 15:38:40 +0100 Subject: [PATCH 05/21] updated maven repository URL --- dhp-build/dhp-code-style/pom.xml | 4 ++-- pom.xml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dhp-build/dhp-code-style/pom.xml b/dhp-build/dhp-code-style/pom.xml index e60e8076e..77aa2aedb 100644 --- a/dhp-build/dhp-code-style/pom.xml +++ b/dhp-build/dhp-code-style/pom.xml @@ -15,12 +15,12 @@ dnet45-snapshots DNet45 Snapshots - http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-snapshots + https://maven.d4science.org/nexus/content/repositories/dnet45-snapshots default dnet45-releases - http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-releases + https://maven.d4science.org/nexus/content/repositories/dnet45-releases diff --git a/pom.xml b/pom.xml index 03c69108d..e9b90a765 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ dnet45-releases D-Net 45 releases - http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-releases + https://maven.d4science.org/nexus/content/repositories/dnet45-releases default false @@ -639,12 +639,12 @@ dnet45-snapshots DNet45 Snapshots - http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-snapshots + https://maven.d4science.org/nexus/content/repositories/dnet45-snapshots default dnet45-releases - http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-releases + https://maven.d4science.org/nexus/content/repositories/dnet45-releases From 5d4e34e26afc5346828a01ae8b5648f2fd908aef Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Sat, 14 Nov 2020 10:32:26 +0100 Subject: [PATCH 06/21] fixed typo in variable name --- .../dhp/oa/graph/merge/oozie_app/workflow.xml | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml index 5af117d68..86fb51042 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/merge/oozie_app/workflow.xml @@ -88,8 +88,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/publication - --prodInputPath${prodInputGgraphPath}/publication + --betaInputPath${betaInputGraphPath}/publication + --prodInputPath${prodInputGraphPath}/publication --outputPath${graphOutputPath}/publication --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Publication --priority${priority} @@ -115,8 +115,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/dataset - --prodInputPath${prodInputGgraphPath}/dataset + --betaInputPath${betaInputGraphPath}/dataset + --prodInputPath${prodInputGraphPath}/dataset --outputPath${graphOutputPath}/dataset --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Dataset --priority${priority} @@ -142,8 +142,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/otherresearchproduct - --prodInputPath${prodInputGgraphPath}/otherresearchproduct + --betaInputPath${betaInputGraphPath}/otherresearchproduct + --prodInputPath${prodInputGraphPath}/otherresearchproduct --outputPath${graphOutputPath}/otherresearchproduct --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct --priority${priority} @@ -169,8 +169,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/software - --prodInputPath${prodInputGgraphPath}/software + --betaInputPath${betaInputGraphPath}/software + --prodInputPath${prodInputGraphPath}/software --outputPath${graphOutputPath}/software --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Software --priority${priority} @@ -196,8 +196,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/datasource - --prodInputPath${prodInputGgraphPath}/datasource + --betaInputPath${betaInputGraphPath}/datasource + --prodInputPath${prodInputGraphPath}/datasource --outputPath${graphOutputPath}/datasource --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Datasource --priority${priority} @@ -223,8 +223,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/organization - --prodInputPath${prodInputGgraphPath}/organization + --betaInputPath${betaInputGraphPath}/organization + --prodInputPath${prodInputGraphPath}/organization --outputPath${graphOutputPath}/organization --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Organization --priority${priority} @@ -250,8 +250,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/project - --prodInputPath${prodInputGgraphPath}/project + --betaInputPath${betaInputGraphPath}/project + --prodInputPath${prodInputGraphPath}/project --outputPath${graphOutputPath}/project --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Project --priority${priority} @@ -277,8 +277,8 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --betaInputPath${betaInputGgraphPath}/relation - --prodInputPath${prodInputGgraphPath}/relation + --betaInputPath${betaInputGraphPath}/relation + --prodInputPath${prodInputGraphPath}/relation --outputPath${graphOutputPath}/relation --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Relation --priority${priority} From 331d62180060caee96f38431a65cae0960be7eca Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Sat, 14 Nov 2020 12:16:15 +0100 Subject: [PATCH 07/21] added test resource --- .../eu/dnetlib/dhp/oa/graph/raw/oaf_orp.xml | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_orp.xml diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_orp.xml b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_orp.xml new file mode 100644 index 000000000..6c83073de --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_orp.xml @@ -0,0 +1,84 @@ + + +
+ pensoft_____::00ea4a1cd53806a97d62ea6bf268f2a2 + 10.3897/oneeco.2.e13718 + + + + + + 2020-03-23T00:20:51.392Z + 2020-03-23T00:26:59.078Z + pensoft_____ +
+ + Ecosystem Service capacity is higher in areas of multiple designation types + Nikolaidou,Charitini + Votsi,Nefta + Sgardelis,Steanos + Halley,John + Pantis,John + Tsiafouli,Maria + 2017 + The implementation of the Ecosystem Service (ES) concept into practice might be a challenging task as it has to take into account previous “traditional” policies and approaches that have evaluated nature and biodiversity differently. Among them the Habitat (92/43/EC) and Bird Directives (79/409/EC), the Water Framework Directive (2000/60/EC), and the Noise Directive (2002/49/EC) have led to the evaluation/designation of areas in Europe with different criteria. In this study our goal was to understand how the ES capacity of an area is related to its designation and if areas with multiple designations have higher capacity in providing ES. We selected four catchments in Greece with a great variety of characteristics covering over 25% of the national territory. Inside the catchments we assessed the ES capacity (following the methodology of Burkhard et al. 2009) of areas designated as Natura 2000 sites, Quiet areas and Wetlands or Water bodies and found those areas that have multiple designations. Data were analyzed by GLM to reveal differences regarding the ES capacity among the different types of areas. We also investigated by PCA synergies and trade-offs among different kinds of ES and tested for correlations among landscape properties, such as elevation, aspect and slope and the ES potential. Our results show that areas with different types or multiple designations have a different capacity in providing ES. Areas of one designation type (Protected or Quiet Areas) had in general intermediate scores in most ES but scores were higher compared to areas with no designation, which displayed stronger capacity in provisioning services. Among Protected Areas and Quiet Areas the latter scored better in general. Areas that combined both designation types (Protected and Quiet Areas) showed the highest capacity in 13 out of 29 ES, that were mostly linked with natural and forest ecosystems. We found significant synergies among most regulating, supporting and cultural ES which in turn display trade-offs with provisioning services. The different ES are spatially related and display strong correlation with landscape properties, such as elevation and slope. We suggest that the designation status of an area can be used as an alternative tool for environmental policy, indicating the capacity for ES provision. Multiple designations of areas can be used as proxies for locating ES “hotspots”. This integration of “traditional” evaluation and designation and the “newer” ES concept forms a time- and cost-effective way to be adopted by stakeholders and policy-makers in order to start complying with new standards and demands for nature conservation and environmental management. + text/html + https://doi.org/10.3897/oneeco.2.e13718 + https://oneecosystem.pensoft.net/article/13718/ + eng + Pensoft Publishers + info:eu-repo/semantics/altIdentifier/eissn/2367-8194 + info:eu-repo/grantAgreement/EC/FP7/226852 + One Ecosystem 2: e13718 + One Ecosystem 2: e13718 + One Ecosystem 2: e13718 + Ecosystem Services hotspots + Natura 2000 + Quiet Protected Areas + Biodiversity + Agriculture + Elevation + Slope + Ecosystem Service trade-offs and synergies + cultural services + provisioning services + regulating services + supporting services + Research Article + + 0020 + 2017-01-01 + corda_______::226852 + OPEN + + + 10.3897/oneeco.2.e13718 + https://oneecosystem.pensoft.net/article/13718/ + One Ecosystem + 0001 + + + + + http%3A%2F%2Fzookeys.pensoft.net%2Foai.php + 10.3897/oneeco.2.e13718 + 2017-09-08 + http://www.openarchives.org/OAI/2.0/oai_dc/ + + + + false + false + 0.9 + + + + +
\ No newline at end of file From 4de8c8b237dc8a93a9d4ed3fe7b8745bb4f567d3 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Mon, 16 Nov 2020 10:03:11 +0100 Subject: [PATCH 08/21] fixed workflow variable name --- .../dhp/oa/graph/clean/oozie_app/workflow.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml index 8b6ca9de6..992d8c40e 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/clean/oozie_app/workflow.xml @@ -108,7 +108,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/publication + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/publication --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Publication --isLookupUrl${isLookupUrl} @@ -134,7 +134,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/dataset + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/dataset --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Dataset --isLookupUrl${isLookupUrl} @@ -160,7 +160,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/otherresearchproduct + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/otherresearchproduct --graphTableClassNameeu.dnetlib.dhp.schema.oaf.OtherResearchProduct --isLookupUrl${isLookupUrl} @@ -186,7 +186,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/software + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/software --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Software --isLookupUrl${isLookupUrl} @@ -212,7 +212,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/datasource + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/datasource --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Datasource --isLookupUrl${isLookupUrl} @@ -238,7 +238,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/organization + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/organization --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Organization --isLookupUrl${isLookupUrl} @@ -264,7 +264,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/project + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/project --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Project --isLookupUrl${isLookupUrl} @@ -290,7 +290,7 @@ --conf spark.eventLog.dir=${nameNode}${spark2EventLogDir} --conf spark.sql.shuffle.partitions=7680 - --inputPath${graphInputPath}/relation + --inputPath${workingDir}/grouped_entities --outputPath${graphOutputPath}/relation --graphTableClassNameeu.dnetlib.dhp.schema.oaf.Relation --isLookupUrl${isLookupUrl} From 6ab1ce53c9e96fe719097588b003ad55609c3b8b Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Mon, 16 Nov 2020 10:09:17 +0100 Subject: [PATCH 09/21] fixed condition in result pid cleaning; cleanup --- .../dhp/oa/graph/clean/CleaningFunctions.java | 2 +- .../dispatch_entities_bytype_parameters.json | 26 ------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java index 9f06ea056..4bcce8037 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java @@ -114,7 +114,7 @@ public class CleaningFunctions { .stream() .filter(Objects::nonNull) .filter(sp -> StringUtils.isNotBlank(StringUtils.trim(sp.getValue()))) - .filter(sp -> NONE.equalsIgnoreCase(sp.getValue())) + .filter(sp -> !NONE.equalsIgnoreCase(sp.getValue().trim())) .filter(sp -> Objects.nonNull(sp.getQualifier())) .filter(sp -> StringUtils.isNotBlank(sp.getQualifier().getClassid())) .map(sp -> { diff --git a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json b/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json deleted file mode 100644 index a75ff3653..000000000 --- a/dhp-workflows/dhp-graph-mapper/src/main/resources/eu/dnetlib/dhp/oa/graph/dispatch_entities_bytype_parameters.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "paramName": "issm", - "paramLongName": "isSparkSessionManaged", - "paramDescription": "when true will stop SparkSession after job execution", - "paramRequired": false - }, - { - "paramName": "ep", - "paramLongName": "entitiesPath", - "paramDescription": "the entities path", - "paramRequired": true - }, - { - "paramName": "g", - "paramLongName": "outputPath", - "paramDescription": "the output path to store the dispatched entities", - "paramRequired": true - }, - { - "paramName": "class", - "paramLongName": "graphTableClassName", - "paramDescription": "class name modelling the graph table", - "paramRequired": true - } -] \ No newline at end of file From 628ca54dd32e7957caa9b5150cb07e5b3dfd28f3 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Tue, 17 Nov 2020 12:26:16 +0100 Subject: [PATCH 10/21] disable old maven repository URLs --- pom.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pom.xml b/pom.xml index e9b90a765..d0757f145 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,26 @@ false + + dnet45-releases-old + http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-releases + + false + + + false + + + + dnet45-snapshots-old + http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-snapshots + + false + + + false + + From cfc01f136e2dd10edd9ca006ded209de01c736ec Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Tue, 17 Nov 2020 12:27:06 +0100 Subject: [PATCH 11/21] PID filtering based on a blacklist --- .../dhp/oa/graph/clean/CleaningFunctions.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java index 4bcce8037..e9f783670 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctions.java @@ -1,8 +1,10 @@ package eu.dnetlib.dhp.oa.graph.clean; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -17,7 +19,13 @@ import eu.dnetlib.dhp.schema.oaf.*; public class CleaningFunctions { public static final String ORCID_PREFIX_REGEX = "^http(s?):\\/\\/orcid\\.org\\/"; - public static final String NONE = "none"; + + public static final Set PID_BLACKLIST = new HashSet<>(); + + static { + PID_BLACKLIST.add("none"); + PID_BLACKLIST.add("na"); + } public static T fixVocabularyNames(T value) { if (value instanceof Datasource) { @@ -114,7 +122,7 @@ public class CleaningFunctions { .stream() .filter(Objects::nonNull) .filter(sp -> StringUtils.isNotBlank(StringUtils.trim(sp.getValue()))) - .filter(sp -> !NONE.equalsIgnoreCase(sp.getValue().trim())) + .filter(sp -> !PID_BLACKLIST.contains(sp.getValue().trim().toLowerCase())) .filter(sp -> Objects.nonNull(sp.getQualifier())) .filter(sp -> StringUtils.isNotBlank(sp.getQualifier().getClassid())) .map(sp -> { From 7e0a76a8ac46640945a5285123d7dc392ab04dd6 Mon Sep 17 00:00:00 2001 From: Alessia Bardi Date: Tue, 17 Nov 2020 18:39:25 +0100 Subject: [PATCH 12/21] test fr TextGrid --- .../dnetlib/dhp/oa/graph/raw/MappersTest.java | 16 +++ .../eu/dnetlib/dhp/oa/graph/raw/textgrid.xml | 113 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/textgrid.xml diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java index af9fadb5a..663eb10e2 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java @@ -340,6 +340,22 @@ public class MappersTest { assertTrue(StringUtils.isNotBlank(p.getTitle().get(0).getValue())); } + @Test + void testTextGrid() throws IOException { + final String xml = IOUtils.toString(getClass().getResourceAsStream("textgrid.xml")); + final List list = new OdfToOafMapper(vocs, false).processMdRecord(xml); + + System.out.println("***************"); + System.out.println(new ObjectMapper().writeValueAsString(list)); + System.out.println("***************"); + + final Dataset p = (Dataset) list.get(0); + assertValidId(p.getId()); + assertValidId(p.getCollectedfrom().get(0).getKey()); + assertTrue(StringUtils.isNotBlank(p.getTitle().get(0).getValue())); + System.out.println(p.getTitle().get(0).getValue()); + } + private void assertValidId(final String id) { assertEquals(49, id.length()); assertEquals('|', id.charAt(2)); diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/textgrid.xml b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/textgrid.xml new file mode 100644 index 000000000..d6970ab3e --- /dev/null +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/textgrid.xml @@ -0,0 +1,113 @@ + + + + r3f52792889d::000051aa1f61d77d2c0b340091f8024e + textgrid:q9cv.0 + 2020-11-17T09:34:11.128+01:00 + r3f52792889d + textgrid:q9cv.0 + 2012-01-21T13:35:20Z + 2020-11-17T09:46:21.551+01:00 + + + + hdl:11858/00-1734-0000-0003-7664-F + + + Hoffmann von Fallersleben, August Heinrich + 118552589 + + + + Mailied + August Heinrich Hoffmann von Fallersleben: Unpolitische Lieder von Hoffmann von Fallersleben, 1. + 2. Theil, 1. Theil, Hamburg: Hoffmann und Campe, 1841. + + TextGrid + 2012 + + + tvitt@textgrid.de + + + Digitale Bibliothek + TGPR-372fe6dc-57f2-6cd4-01b5-2c4bbefcfd3c + + + + 2012-01-21T13:35:20Z + 2012-01-21T13:35:20Z + 2012-01-21T13:35:20Z + + + + textgrid:q9cv.0 + http://hdl.handle.net/hdl:11858/00-1734-0000-0003-7664-F + + + hdl:11858/00-1734-0000-0003-7666-B + + + 527 Bytes + + + text/tg.edition+tg.aggregation+xml + + 0 + + Der annotierte Datenbestand der Digitalen Bibliothek inklusive + Metadaten sowie davon einzeln zugängliche Teile sind eine Abwandlung + des Datenbestandes von www.editura.de durch TextGrid und werden + unter der Lizenz Creative Commons Namensnennung 3.0 Deutschland + Lizenz (by-Nennung TextGrid) veröffentlicht. Die Lizenz bezieht sich + nicht auf die der Annotation zu Grunde liegenden allgemeinfreien + Texte (Siehe auch Punkt 2 der Lizenzbestimmungen). + + + + + + + + Hamburg + + + + hdl:11858/00-1734-0000-0003-7664-F + 0021 + 0002 + 2012-01-01 + OPEN + http://creativecommons.org/licenses/by/3.0/de/legalcode + und + + + + + + + https%3A%2F%2Fdev.textgridlab.org%2F1.0%2Ftgoaipmh%2Foai + textgrid:q9cv.0 + 2012-01-21T13:35:20Z + http://schema.datacite.org/oai/oai-1.0/ + + + + false + false + 0.9 + + + + + \ No newline at end of file From 8f87020a5027920578f6bf0aa134ab0eba7cc8fd Mon Sep 17 00:00:00 2001 From: Alessia Bardi Date: Tue, 17 Nov 2020 18:42:09 +0100 Subject: [PATCH 13/21] #56: map relevantDates from aggregated ODF records --- .../eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java index 7124684d5..842638f40 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java @@ -162,16 +162,23 @@ public class OdfToOafMapper extends AbstractMdRecordToOafMapper { for (final Object o : doc.selectNodes("//datacite:date")) { final String dateType = ((Node) o).valueOf("@dateType"); if (StringUtils.isBlank(dateType) - && !dateType.equalsIgnoreCase("Accepted") + || ( !dateType.equalsIgnoreCase("Accepted") && !dateType.equalsIgnoreCase("Issued") && !dateType.equalsIgnoreCase("Updated") - && !dateType.equalsIgnoreCase("Available")) { + && !dateType.equalsIgnoreCase("Available"))) { res .add( structuredProperty( ((Node) o).getText(), "UNKNOWN", "UNKNOWN", DNET_DATA_CITE_DATE, DNET_DATA_CITE_DATE, info)); } + else{ + res + .add( + structuredProperty( + ((Node) o).getText(), dateType, dateType, DNET_DATA_CITE_DATE, DNET_DATA_CITE_DATE, + info)); + } } return res; } From 01a6e039892a0a884a9f5d14748b86b774da212c Mon Sep 17 00:00:00 2001 From: antleb Date: Tue, 17 Nov 2020 23:26:47 +0200 Subject: [PATCH 14/21] starting from first step... --- .../eu/dnetlib/dhp/oa/graph/stats/oozie_app/workflow.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhp-workflows/dhp-stats-update/src/main/resources/eu/dnetlib/dhp/oa/graph/stats/oozie_app/workflow.xml b/dhp-workflows/dhp-stats-update/src/main/resources/eu/dnetlib/dhp/oa/graph/stats/oozie_app/workflow.xml index 20eec37dc..d6cc14e25 100644 --- a/dhp-workflows/dhp-stats-update/src/main/resources/eu/dnetlib/dhp/oa/graph/stats/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-stats-update/src/main/resources/eu/dnetlib/dhp/oa/graph/stats/oozie_app/workflow.xml @@ -46,7 +46,7 @@ - + Action failed, error message[${wf:errorMessage(wf:lastErrorNode())}] From 33da2e3d6c94796ca875aa30fc962c3c6ea54857 Mon Sep 17 00:00:00 2001 From: "michele.artini" Date: Wed, 18 Nov 2020 09:26:20 +0100 Subject: [PATCH 15/21] xpaths for dateOfCollection and dateOfTransformation --- .../raw/AbstractMdRecordToOafMapper.java | 61 ++++++++++++++++--- .../dhp/oa/graph/raw/OdfToOafMapper.java | 19 +++--- .../dnetlib/dhp/oa/graph/raw/MappersTest.java | 4 +- .../dnetlib/dhp/oa/graph/raw/oaf_record.xml | 5 +- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java index da4b5e324..95dd1e1ca 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/AbstractMdRecordToOafMapper.java @@ -1,10 +1,36 @@ package eu.dnetlib.dhp.oa.graph.raw; -import static eu.dnetlib.dhp.schema.common.ModelConstants.*; -import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.*; +import static eu.dnetlib.dhp.schema.common.ModelConstants.DATASET_DEFAULT_RESULTTYPE; +import static eu.dnetlib.dhp.schema.common.ModelConstants.DNET_ACCESS_MODES; +import static eu.dnetlib.dhp.schema.common.ModelConstants.DNET_PID_TYPES; +import static eu.dnetlib.dhp.schema.common.ModelConstants.IS_PRODUCED_BY; +import static eu.dnetlib.dhp.schema.common.ModelConstants.NOT_AVAILABLE; +import static eu.dnetlib.dhp.schema.common.ModelConstants.ORP_DEFAULT_RESULTTYPE; +import static eu.dnetlib.dhp.schema.common.ModelConstants.OUTCOME; +import static eu.dnetlib.dhp.schema.common.ModelConstants.PRODUCES; +import static eu.dnetlib.dhp.schema.common.ModelConstants.PUBLICATION_DEFAULT_RESULTTYPE; +import static eu.dnetlib.dhp.schema.common.ModelConstants.REPOSITORY_PROVENANCE_ACTIONS; +import static eu.dnetlib.dhp.schema.common.ModelConstants.RESULT_PROJECT; +import static eu.dnetlib.dhp.schema.common.ModelConstants.SOFTWARE_DEFAULT_RESULTTYPE; +import static eu.dnetlib.dhp.schema.common.ModelConstants.UNKNOWN; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.createOpenaireId; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.dataInfo; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.field; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.journal; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.keyValue; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.listFields; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.oaiIProvenance; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.qualifier; +import static eu.dnetlib.dhp.schema.oaf.OafMapperUtils.structuredProperty; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.dom4j.Document; @@ -15,7 +41,24 @@ import org.dom4j.Node; import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; import eu.dnetlib.dhp.schema.common.LicenseComparator; import eu.dnetlib.dhp.schema.common.ModelConstants; -import eu.dnetlib.dhp.schema.oaf.*; +import eu.dnetlib.dhp.schema.oaf.Author; +import eu.dnetlib.dhp.schema.oaf.Context; +import eu.dnetlib.dhp.schema.oaf.DataInfo; +import eu.dnetlib.dhp.schema.oaf.Dataset; +import eu.dnetlib.dhp.schema.oaf.Field; +import eu.dnetlib.dhp.schema.oaf.GeoLocation; +import eu.dnetlib.dhp.schema.oaf.Instance; +import eu.dnetlib.dhp.schema.oaf.Journal; +import eu.dnetlib.dhp.schema.oaf.KeyValue; +import eu.dnetlib.dhp.schema.oaf.OAIProvenance; +import eu.dnetlib.dhp.schema.oaf.Oaf; +import eu.dnetlib.dhp.schema.oaf.OtherResearchProduct; +import eu.dnetlib.dhp.schema.oaf.Publication; +import eu.dnetlib.dhp.schema.oaf.Qualifier; +import eu.dnetlib.dhp.schema.oaf.Relation; +import eu.dnetlib.dhp.schema.oaf.Result; +import eu.dnetlib.dhp.schema.oaf.Software; +import eu.dnetlib.dhp.schema.oaf.StructuredProperty; public abstract class AbstractMdRecordToOafMapper { @@ -92,10 +135,10 @@ public abstract class AbstractMdRecordToOafMapper { } protected String getResultType(final Document doc, final List instances) { - String type = doc.valueOf("//dr:CobjCategory/@type"); + final String type = doc.valueOf("//dr:CobjCategory/@type"); if (StringUtils.isBlank(type) & vocs.vocabularyExists(ModelConstants.DNET_RESULT_TYPOLOGIES)) { - String instanceType = instances + final String instanceType = instances .stream() .map(i -> i.getInstancetype().getClassid()) .findFirst() @@ -256,13 +299,11 @@ public abstract class AbstractMdRecordToOafMapper { r.setDataInfo(info); r.setLastupdatetimestamp(lastUpdateTimestamp); r.setId(createOpenaireId(50, doc.valueOf("//dri:objIdentifier"), false)); - r.setOriginalId(Arrays.asList(findOriginalId(doc))); - r.setCollectedfrom(Arrays.asList(collectedFrom)); r.setPid(prepareResultPids(doc, info)); - r.setDateofcollection(doc.valueOf("//dr:dateOfCollection")); - r.setDateoftransformation(doc.valueOf("//dr:dateOfTransformation")); + r.setDateofcollection(doc.valueOf("//dr:dateOfCollection|//dri:dateOfCollection")); + r.setDateoftransformation(doc.valueOf("//dr:dateOfTransformation|//dri:dateOfTransformation")); r.setExtraInfo(new ArrayList<>()); // NOT PRESENT IN MDSTORES r.setOaiprovenance(prepareOAIprovenance(doc)); r.setAuthor(prepareAuthors(doc, info)); diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java index 842638f40..b432a51df 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java @@ -162,22 +162,21 @@ public class OdfToOafMapper extends AbstractMdRecordToOafMapper { for (final Object o : doc.selectNodes("//datacite:date")) { final String dateType = ((Node) o).valueOf("@dateType"); if (StringUtils.isBlank(dateType) - || ( !dateType.equalsIgnoreCase("Accepted") - && !dateType.equalsIgnoreCase("Issued") - && !dateType.equalsIgnoreCase("Updated") - && !dateType.equalsIgnoreCase("Available"))) { + || (!dateType.equalsIgnoreCase("Accepted") + && !dateType.equalsIgnoreCase("Issued") + && !dateType.equalsIgnoreCase("Updated") + && !dateType.equalsIgnoreCase("Available"))) { res .add( structuredProperty( ((Node) o).getText(), "UNKNOWN", "UNKNOWN", DNET_DATA_CITE_DATE, DNET_DATA_CITE_DATE, info)); - } - else{ + } else { res - .add( - structuredProperty( - ((Node) o).getText(), dateType, dateType, DNET_DATA_CITE_DATE, DNET_DATA_CITE_DATE, - info)); + .add( + structuredProperty( + ((Node) o).getText(), dateType, dateType, DNET_DATA_CITE_DATE, DNET_DATA_CITE_DATE, + info)); } } return res; diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java index 663eb10e2..2d4cccdfb 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/raw/MappersTest.java @@ -78,6 +78,8 @@ public class MappersTest { assertTrue(StringUtils.isNotBlank(p.getTitle().get(0).getValue())); assertFalse(p.getDataInfo().getInvisible()); assertTrue(p.getSource().size() == 1); + assertTrue(StringUtils.isNotBlank(p.getDateofcollection())); + assertTrue(StringUtils.isNotBlank(p.getDateoftransformation())); assertTrue(p.getAuthor().size() > 0); final Optional author = p @@ -329,7 +331,7 @@ public class MappersTest { @Test void testODFRecord() throws IOException { final String xml = IOUtils.toString(getClass().getResourceAsStream("odf_record.xml")); - List list = new OdfToOafMapper(vocs, false).processMdRecord(xml); + final List list = new OdfToOafMapper(vocs, false).processMdRecord(xml); System.out.println("***************"); System.out.println(new ObjectMapper().writeValueAsString(list)); System.out.println("***************"); diff --git a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_record.xml b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_record.xml index 3b2658bcf..2c6c98ebb 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_record.xml +++ b/dhp-workflows/dhp-graph-mapper/src/test/resources/eu/dnetlib/dhp/oa/graph/raw/oaf_record.xml @@ -7,13 +7,12 @@
pensoft_____::00ea4a1cd53806a97d62ea6bf268f2a2 10.3897/oneeco.2.e13718 - - 2020-03-23T00:20:51.392Z - 2020-03-23T00:26:59.078Z + 2020-03-23T00:20:51.392Z + 2020-03-23T00:26:59.078Z pensoft_____
From be7b310cef8d729b925397f89b49827f9bd44068 Mon Sep 17 00:00:00 2001 From: Alessia Bardi Date: Wed, 18 Nov 2020 10:01:20 +0100 Subject: [PATCH 16/21] rel semantcis ignore case --- .../main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java index 842638f40..16fde4517 100644 --- a/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java +++ b/dhp-workflows/dhp-graph-mapper/src/main/java/eu/dnetlib/dhp/oa/graph/raw/OdfToOafMapper.java @@ -348,7 +348,7 @@ public class OdfToOafMapper extends AbstractMdRecordToOafMapper { getRelation( otherId, docId, RESULT_RESULT, SUPPLEMENT, IS_SUPPLEMENTED_BY, collectedFrom, info, lastUpdateTimestamp)); - } else if (type.equals("IsPartOf")) { + } else if (type.equalsIgnoreCase("IsPartOf")) { res .add( From 8177ce793991b4741f2cd01beb9487e1e3ae9f28 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Wed, 18 Nov 2020 10:58:05 +0100 Subject: [PATCH 17/21] test for XmlIndexingJob based on a local miniSolrCluster --- .../oa/graph/clean/CleaningFunctionTest.java | 7 +- dhp-workflows/dhp-graph-provision/pom.xml | 28 +- .../dhp/oa/provision/ProvisionConstants.java | 8 + .../oa/provision/SolrAdminApplication.java | 9 +- .../dhp/oa/provision/SolrApplication.java | 40 - .../dhp/oa/provision/XmlIndexingJob.java | 127 +- .../oa/provision/utils/ISLookupClient.java | 95 ++ .../utils/StreamingInputDocumentFactory.java | 10 +- .../provision/SolrAdminApplicationTest.java | 93 +- .../eu/dnetlib/dhp/oa/provision/SolrTest.java | 108 ++ .../dhp/oa/provision/XmlIndexingJobTest.java | 99 ++ .../solr/conf/testConfig/elevate.xml | 31 + .../solr/conf/testConfig/managed-schema | 1407 +++++------------ .../solr/conf/testConfig/solrconfig.xml | 228 +-- .../dnetlib/dhp/oa/provision/xml/part-00000 | Bin 0 -> 293298 bytes 15 files changed, 963 insertions(+), 1327 deletions(-) delete mode 100644 dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrApplication.java create mode 100644 dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/ISLookupClient.java create mode 100644 dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java create mode 100644 dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java create mode 100644 dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/elevate.xml create mode 100644 dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/xml/part-00000 diff --git a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctionTest.java b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctionTest.java index 8a53c3a50..cb34b0cb3 100644 --- a/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctionTest.java +++ b/dhp-workflows/dhp-graph-mapper/src/test/java/eu/dnetlib/dhp/oa/graph/clean/CleaningFunctionTest.java @@ -7,8 +7,6 @@ import static org.mockito.Mockito.lenient; import java.io.IOException; import java.util.List; import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.io.IOUtils; @@ -21,7 +19,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.fasterxml.jackson.databind.ObjectMapper; import eu.dnetlib.dhp.oa.graph.raw.common.VocabularyGroup; -import eu.dnetlib.dhp.schema.oaf.*; +import eu.dnetlib.dhp.schema.oaf.Publication; +import eu.dnetlib.dhp.schema.oaf.Qualifier; +import eu.dnetlib.dhp.schema.oaf.Result; +import eu.dnetlib.dhp.schema.oaf.StructuredProperty; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; diff --git a/dhp-workflows/dhp-graph-provision/pom.xml b/dhp-workflows/dhp-graph-provision/pom.xml index 8194d4d01..38b575f3e 100644 --- a/dhp-workflows/dhp-graph-provision/pom.xml +++ b/dhp-workflows/dhp-graph-provision/pom.xml @@ -14,6 +14,16 @@ org.apache.spark spark-core_2.11 + + + org.slf4j + slf4j-api + + + org.slf4j + jul-to-slf4j + + org.apache.spark @@ -22,6 +32,12 @@ com.jayway.jsonpath json-path + + + org.slf4j + slf4j-api + + dom4j @@ -82,9 +98,6 @@ org.codehaus.woodstox * - - - com.github.ben-manes.caffeine * @@ -109,11 +122,10 @@ org.apache.hadoop * - - - - - + + org.apache.zookeeper + zookeeper + diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/ProvisionConstants.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/ProvisionConstants.java index 9bc3706cd..d13b54e01 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/ProvisionConstants.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/ProvisionConstants.java @@ -3,6 +3,10 @@ package eu.dnetlib.dhp.oa.provision; public class ProvisionConstants { + public static final String LAYOUT = "index"; + public static final String INTERPRETATION = "openaire"; + public static final String SEPARATOR = "-"; + public static final int MAX_EXTERNAL_ENTITIES = 50; public static final int MAX_AUTHORS = 200; public static final int MAX_AUTHOR_FULLNAME_LENGTH = 1000; @@ -11,4 +15,8 @@ public class ProvisionConstants { public static final int MAX_ABSTRACT_LENGTH = 100000; public static final int MAX_INSTANCES = 10; + public static String getCollectionName(String format) { + return format + SEPARATOR + LAYOUT + SEPARATOR + INTERPRETATION; + } + } diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplication.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplication.java index 8c8947298..5fe452efe 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplication.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplication.java @@ -14,11 +14,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; import eu.dnetlib.dhp.oa.provision.utils.ZkServers; import eu.dnetlib.dhp.utils.ISLookupClientFactory; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; -public class SolrAdminApplication extends SolrApplication implements Closeable { +public class SolrAdminApplication implements Closeable { private static final Logger log = LoggerFactory.getLogger(SolrAdminApplication.class); @@ -54,12 +55,12 @@ public class SolrAdminApplication extends SolrApplication implements Closeable { .orElse(false); log.info("commit: {}", commit); - final ISLookUpService isLookup = ISLookupClientFactory.getLookUpService(isLookupUrl); + final ISLookupClient isLookup = new ISLookupClient(ISLookupClientFactory.getLookUpService(isLookupUrl)); - final String zkHost = getZkHost(isLookup); + final String zkHost = isLookup.getZkHost(); log.info("zkHost: {}", zkHost); - final String collection = format + SEPARATOR + LAYOUT + SEPARATOR + INTERPRETATION; + final String collection = ProvisionConstants.getCollectionName(format); log.info("collection: {}", collection); try (SolrAdminApplication app = new SolrAdminApplication(zkHost)) { diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrApplication.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrApplication.java deleted file mode 100644 index a824c6c2c..000000000 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/SolrApplication.java +++ /dev/null @@ -1,40 +0,0 @@ - -package eu.dnetlib.dhp.oa.provision; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; - -public abstract class SolrApplication { - - private static final Logger log = LoggerFactory.getLogger(SolrApplication.class); - - protected static final String LAYOUT = "index"; - protected static final String INTERPRETATION = "openaire"; - protected static final String SEPARATOR = "-"; - protected static final String DATE_FORMAT = "yyyy-MM-dd'T'hh:mm:ss'Z'"; - - /** - * Method retrieves from the information system the zookeeper quorum of the Solr server - * - * @param isLookup - * @return the zookeeper quorum of the Solr server - * @throws ISLookUpException - */ - protected static String getZkHost(ISLookUpService isLookup) throws ISLookUpException { - return doLookup( - isLookup, - "for $x in /RESOURCE_PROFILE[.//RESOURCE_TYPE/@value='IndexServiceResourceType'] return $x//PROTOCOL[./@name='solr']/@address/string()"); - } - - protected static String doLookup(ISLookUpService isLookup, String xquery) throws ISLookUpException { - log.info(String.format("running xquery: %s", xquery)); - final String res = isLookup.getResourceProfileByQuery(xquery); - log.info(String.format("got response (100 chars): %s", StringUtils.left(res, 100) + " ...")); - return res; - } - -} diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java index 5b5596162..c51dc3b58 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java @@ -16,31 +16,40 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.io.Text; import org.apache.solr.common.SolrInputDocument; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.rdd.RDD; +import org.apache.spark.sql.SparkSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.lucidworks.spark.util.SolrSupport; import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; import eu.dnetlib.dhp.oa.provision.utils.StreamingInputDocumentFactory; import eu.dnetlib.dhp.utils.ISLookupClientFactory; import eu.dnetlib.dhp.utils.saxon.SaxonTransformerFactory; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException; import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; -public class XmlIndexingJob extends SolrApplication { +public class XmlIndexingJob { private static final Logger log = LoggerFactory.getLogger(XmlIndexingJob.class); private static final Integer DEFAULT_BATCH_SIZE = 1000; + protected static final String DATE_FORMAT = "yyyy-MM-dd'T'hh:mm:ss'Z'"; + + private String inputPath; + + private String format; + + private int batchSize; + + private SparkSession spark; + public static void main(String[] args) throws Exception { final ArgumentApplicationParser parser = new ArgumentApplicationParser( @@ -60,9 +69,6 @@ public class XmlIndexingJob extends SolrApplication { final String inputPath = parser.get("inputPath"); log.info("inputPath: {}", inputPath); - final String isLookupUrl = parser.get("isLookupUrl"); - log.info("isLookupUrl: {}", isLookupUrl); - final String format = parser.get("format"); log.info("format: {}", format); @@ -71,16 +77,36 @@ public class XmlIndexingJob extends SolrApplication { : DEFAULT_BATCH_SIZE; log.info("batchSize: {}", batchSize); - final ISLookUpService isLookup = ISLookupClientFactory.getLookUpService(isLookupUrl); - final String fields = getLayoutSource(isLookup, format); + final SparkConf conf = new SparkConf(); + + runWithSparkSession( + conf, + isSparkSessionManaged, + spark -> { + final String isLookupUrl = parser.get("isLookupUrl"); + log.info("isLookupUrl: {}", isLookupUrl); + final ISLookupClient isLookup = new ISLookupClient(ISLookupClientFactory.getLookUpService(isLookupUrl)); + new XmlIndexingJob(spark, inputPath, format, batchSize).run(isLookup); + }); + } + + public XmlIndexingJob(SparkSession spark, String inputPath, String format, Integer batchSize) { + this.spark = spark; + this.inputPath = inputPath; + this.format = format; + this.batchSize = batchSize; + } + + public void run(ISLookupClient isLookup) throws ISLookUpException, TransformerException { + final String fields = isLookup.getLayoutSource(format); log.info("fields: {}", fields); - final String xslt = getLayoutTransformer(isLookup); + final String xslt = isLookup.getLayoutTransformer(); - final String dsId = getDsId(format, isLookup); + final String dsId = isLookup.getDsId(format); log.info("dsId: {}", dsId); - final String zkHost = getZkHost(isLookup); + final String zkHost = isLookup.getZkHost(); log.info("zkHost: {}", zkHost); final String version = getRecordDatestamp(); @@ -88,24 +114,17 @@ public class XmlIndexingJob extends SolrApplication { final String indexRecordXslt = getLayoutTransformer(format, fields, xslt); log.info("indexRecordTransformer {}", indexRecordXslt); - final SparkConf conf = new SparkConf(); + final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); - runWithSparkSession( - conf, - isSparkSessionManaged, - spark -> { - final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); + RDD docs = sc + .sequenceFile(inputPath, Text.class, Text.class) + .map(t -> t._2().toString()) + .map(s -> toIndexRecord(SaxonTransformerFactory.newInstance(indexRecordXslt), s)) + .map(s -> new StreamingInputDocumentFactory(version, dsId).parseDocument(s)) + .rdd(); - RDD docs = sc - .sequenceFile(inputPath, Text.class, Text.class) - .map(t -> t._2().toString()) - .map(s -> toIndexRecord(SaxonTransformerFactory.newInstance(indexRecordXslt), s)) - .map(s -> new StreamingInputDocumentFactory(version, dsId).parseDocument(s)) - .rdd(); - - final String collection = format + SEPARATOR + LAYOUT + SEPARATOR + INTERPRETATION; - SolrSupport.indexDocs(zkHost, collection, batchSize, docs); - }); + final String collection = ProvisionConstants.getCollectionName(format); + SolrSupport.indexDocs(zkHost, collection, batchSize, docs); } protected static String toIndexRecord(Transformer tr, final String record) { @@ -151,56 +170,4 @@ public class XmlIndexingJob extends SolrApplication { return new SimpleDateFormat(DATE_FORMAT).format(new Date()); } - /** - * Method retrieves from the information system the list of fields associated to the given MDFormat name - * - * @param isLookup the ISLookup service stub - * @param format the Metadata format name - * @return the string representation of the list of fields to be indexed - * @throws ISLookUpDocumentNotFoundException - * @throws ISLookUpException - */ - private static String getLayoutSource(final ISLookUpService isLookup, final String format) - throws ISLookUpDocumentNotFoundException, ISLookUpException { - return doLookup( - isLookup, - String - .format( - "collection('')//RESOURCE_PROFILE[.//RESOURCE_TYPE/@value = 'MDFormatDSResourceType' and .//NAME='%s']//LAYOUT[@name='%s']", - format, LAYOUT)); - } - - /** - * Method retrieves from the information system the openaireLayoutToRecordStylesheet - * - * @param isLookup the ISLookup service stub - * @return the string representation of the XSLT contained in the transformation rule profile - * @throws ISLookUpDocumentNotFoundException - * @throws ISLookUpException - */ - private static String getLayoutTransformer(ISLookUpService isLookup) throws ISLookUpException { - return doLookup( - isLookup, - "collection('/db/DRIVER/TransformationRuleDSResources/TransformationRuleDSResourceType')" - + "//RESOURCE_PROFILE[./BODY/CONFIGURATION/SCRIPT/TITLE/text() = 'openaireLayoutToRecordStylesheet']//CODE/node()"); - } - - /** - * Method retrieves from the information system the IndexDS profile ID associated to the given MDFormat name - * - * @param format - * @param isLookup - * @return the IndexDS identifier - * @throws ISLookUpException - */ - private static String getDsId(String format, ISLookUpService isLookup) throws ISLookUpException { - return doLookup( - isLookup, - String - .format( - "collection('/db/DRIVER/IndexDSResources/IndexDSResourceType')" - + "//RESOURCE_PROFILE[./BODY/CONFIGURATION/METADATA_FORMAT/text() = '%s']//RESOURCE_IDENTIFIER/@value/string()", - format)); - } - } diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/ISLookupClient.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/ISLookupClient.java new file mode 100644 index 000000000..29a51cb29 --- /dev/null +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/ISLookupClient.java @@ -0,0 +1,95 @@ + +package eu.dnetlib.dhp.oa.provision.utils; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.dnetlib.dhp.oa.provision.ProvisionConstants; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; + +public class ISLookupClient { + + private static final Logger log = LoggerFactory.getLogger(ISLookupClient.class); + + private ISLookUpService isLookup; + + public ISLookupClient(ISLookUpService isLookup) { + this.isLookup = isLookup; + } + + /** + * Method retrieves from the information system the list of fields associated to the given MDFormat name + * + * @param format the Metadata format name + * @return the string representation of the list of fields to be indexed + * @throws ISLookUpDocumentNotFoundException + * @throws ISLookUpException + */ + public String getLayoutSource(final String format) + throws ISLookUpDocumentNotFoundException, ISLookUpException { + return doLookup( + String + .format( + "collection('')//RESOURCE_PROFILE[.//RESOURCE_TYPE/@value = 'MDFormatDSResourceType' and .//NAME='%s']//LAYOUT[@name='%s']", + format, ProvisionConstants.LAYOUT)); + } + + /** + * Method retrieves from the information system the openaireLayoutToRecordStylesheet + * + * @return the string representation of the XSLT contained in the transformation rule profile + * @throws ISLookUpDocumentNotFoundException + * @throws ISLookUpException + */ + public String getLayoutTransformer() throws ISLookUpException { + return doLookup( + "collection('/db/DRIVER/TransformationRuleDSResources/TransformationRuleDSResourceType')" + + "//RESOURCE_PROFILE[./BODY/CONFIGURATION/SCRIPT/TITLE/text() = 'openaireLayoutToRecordStylesheet']//CODE/node()"); + } + + /** + * Method retrieves from the information system the IndexDS profile ID associated to the given MDFormat name + * + * @param format + * @return the IndexDS identifier + * @throws ISLookUpException + */ + public String getDsId(String format) throws ISLookUpException { + return doLookup( + String + .format( + "collection('/db/DRIVER/IndexDSResources/IndexDSResourceType')" + + "//RESOURCE_PROFILE[./BODY/CONFIGURATION/METADATA_FORMAT/text() = '%s']//RESOURCE_IDENTIFIER/@value/string()", + format)); + } + + /** + * Method retrieves from the information system the zookeeper quorum of the Solr server + * + * @return the zookeeper quorum of the Solr server + * @throws ISLookUpException + */ + public String getZkHost() throws ISLookUpException { + return doLookup( + "for $x in /RESOURCE_PROFILE[.//RESOURCE_TYPE/@value='IndexServiceResourceType'] return $x//PROTOCOL[./@name='solr']/@address/string()"); + } + + private String doLookup(String xquery) throws ISLookUpException { + log.info(String.format("running xquery: %s", xquery)); + final String res = getIsLookup().getResourceProfileByQuery(xquery); + log.info(String.format("got response (100 chars): %s", StringUtils.left(res, 100) + " ...")); + return res; + } + + public ISLookUpService getIsLookup() { + return isLookup; + } + + public void setIsLookup(ISLookUpService isLookup) { + this.isLookup = isLookup; + } + +} diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/StreamingInputDocumentFactory.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/StreamingInputDocumentFactory.java index 3e8abbd9f..f16ee260f 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/StreamingInputDocumentFactory.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/utils/StreamingInputDocumentFactory.java @@ -46,11 +46,6 @@ public class StreamingInputDocumentFactory { private static final String INDEX_RECORD_ID = INDEX_FIELD_PREFIX + "indexrecordidentifier"; - private static final String outFormat = "yyyy-MM-dd'T'hh:mm:ss'Z'"; - - private static final List dateFormats = Arrays - .asList("yyyy-MM-dd'T'hh:mm:ss", "yyyy-MM-dd", "dd-MM-yyyy", "dd/MM/yyyy", "yyyy"); - private static final String DEFAULTDNETRESULT = "dnetResult"; private static final String TARGETFIELDS = "targetFields"; @@ -125,13 +120,12 @@ public class StreamingInputDocumentFactory { } if (!indexDocument.containsKey(INDEX_RECORD_ID)) { - indexDocument.clear(); - System.err.println("missing indexrecord id:\n" + inputDocument); + throw new IllegalStateException("cannot extract record ID from: " + inputDocument); } return indexDocument; } catch (XMLStreamException e) { - return new SolrInputDocument(); + throw new IllegalStateException(e); } } diff --git a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplicationTest.java b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplicationTest.java index cbd7b2de2..33def91b3 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplicationTest.java +++ b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrAdminApplicationTest.java @@ -1,107 +1,18 @@ package eu.dnetlib.dhp.oa.provision; -import java.io.File; -import java.nio.file.Path; - -import org.apache.solr.client.solrj.SolrResponse; -import org.apache.solr.client.solrj.embedded.JettyConfig; -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.XMLResponseParser; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.client.solrj.request.ConfigSetAdminRequest; -import org.apache.solr.client.solrj.request.QueryRequest; -import org.apache.solr.client.solrj.request.RequestWriter; -import org.apache.solr.client.solrj.response.CollectionAdminResponse; -import org.apache.solr.client.solrj.response.ConfigSetAdminResponse; import org.apache.solr.client.solrj.response.SolrPingResponse; import org.apache.solr.client.solrj.response.UpdateResponse; -import org.apache.solr.cloud.MiniSolrCloudCluster; -import org.apache.solr.common.params.CollectionParams; -import org.apache.solr.common.params.CoreAdminParams; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.util.NamedList; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import junit.framework.Assert; -public class SolrAdminApplicationTest { - - private static final Logger log = LoggerFactory.getLogger(SolrAdminApplicationTest.class); - public static final String DEFAULT_COLLECTION = "testCollection"; - public static final String CONFIG_NAME = "testConfig"; - - private static MiniSolrCloudCluster miniCluster; - private static CloudSolrClient cloudSolrClient; - - @TempDir - public static Path tempDir; - - @BeforeAll - public static void setup() throws Exception { - - // random unassigned HTTP port - final int jettyPort = 0; - - final JettyConfig jettyConfig = JettyConfig.builder().setPort(jettyPort).build(); - - // create a MiniSolrCloudCluster instance - miniCluster = new MiniSolrCloudCluster(2, tempDir, jettyConfig); - - // Upload Solr configuration directory to ZooKeeper - String solrZKConfigDir = "src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig"; - File configDir = new File(solrZKConfigDir); - - miniCluster.uploadConfigSet(configDir.toPath(), CONFIG_NAME); - - // override settings in the solrconfig include - System.setProperty("solr.tests.maxBufferedDocs", "100000"); - System.setProperty("solr.tests.maxIndexingThreads", "-1"); - System.setProperty("solr.tests.ramBufferSizeMB", "100"); - - // use non-test classes so RandomizedRunner isn't necessary - System.setProperty("solr.tests.mergeScheduler", "org.apache.lucene.index.ConcurrentMergeScheduler"); - System.setProperty("solr.directoryFactory", "solr.RAMDirectoryFactory"); - - cloudSolrClient = miniCluster.getSolrClient(); - cloudSolrClient.setRequestWriter(new RequestWriter()); - cloudSolrClient.setParser(new XMLResponseParser()); - cloudSolrClient.setDefaultCollection(DEFAULT_COLLECTION); - cloudSolrClient.connect(); - - log.info(new ConfigSetAdminRequest.List().process(cloudSolrClient).toString()); - log.info(CollectionAdminRequest.ClusterStatus.getClusterStatus().process(cloudSolrClient).toString()); - - createCollection(cloudSolrClient, DEFAULT_COLLECTION, 2, 1, CONFIG_NAME); - } - - @AfterAll - public static void shutDown() throws Exception { - miniCluster.shutdown(); - } - - protected static NamedList createCollection(CloudSolrClient client, String name, int numShards, - int replicationFactor, String configName) throws Exception { - ModifiableSolrParams modParams = new ModifiableSolrParams(); - modParams.set(CoreAdminParams.ACTION, CollectionParams.CollectionAction.CREATE.name()); - modParams.set("name", name); - modParams.set("numShards", numShards); - modParams.set("replicationFactor", replicationFactor); - modParams.set("collection.configName", configName); - QueryRequest request = new QueryRequest(modParams); - request.setPath("/admin/collections"); - return client.request(request); - } +public class SolrAdminApplicationTest extends SolrTest { @Test public void testPing() throws Exception { - SolrPingResponse pingResponse = cloudSolrClient.ping(); + SolrPingResponse pingResponse = miniCluster.getSolrClient().ping(); log.info("pingResponse: '{}'", pingResponse.getStatus()); Assert.assertTrue(pingResponse.getStatus() == 0); } diff --git a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java new file mode 100644 index 000000000..426c8e678 --- /dev/null +++ b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java @@ -0,0 +1,108 @@ + +package eu.dnetlib.dhp.oa.provision; + +import java.io.File; +import java.nio.file.Path; + +import org.apache.commons.io.FileUtils; +import org.apache.solr.client.solrj.embedded.JettyConfig; +import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.request.CollectionAdminRequest; +import org.apache.solr.client.solrj.request.ConfigSetAdminRequest; +import org.apache.solr.client.solrj.request.QueryRequest; +import org.apache.solr.cloud.MiniSolrCloudCluster; +import org.apache.solr.common.params.CollectionParams; +import org.apache.solr.common.params.CoreAdminParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.NamedList; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class SolrTest { + + protected static final Logger log = LoggerFactory.getLogger(SolrTest.class); + + protected static final String FORMAT = "test"; + protected static final String DEFAULT_COLLECTION = FORMAT + "-index-openaire"; + protected static final String CONFIG_NAME = "testConfig"; + + protected static MiniSolrCloudCluster miniCluster; + + @TempDir + public static Path workingDir; + + @BeforeAll + public static void setup() throws Exception { + + // random unassigned HTTP port + final int jettyPort = 0; + final JettyConfig jettyConfig = JettyConfig.builder().setPort(jettyPort).build(); + + log.info(String.format("working directory: %s", workingDir.toString())); + System.setProperty("solr.log.dir", workingDir.resolve("logs").toString()); + + // create a MiniSolrCloudCluster instance + miniCluster = new MiniSolrCloudCluster(2, workingDir.resolve("solr"), jettyConfig); + + // Upload Solr configuration directory to ZooKeeper + String solrZKConfigDir = "src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig"; + File configDir = new File(solrZKConfigDir); + + miniCluster.uploadConfigSet(configDir.toPath(), CONFIG_NAME); + + // override settings in the solrconfig include + // System.setProperty("solr.tests.maxBufferedDocs", "100000"); + // System.setProperty("solr.tests.maxIndexingThreads", "-1"); + // System.setProperty("solr.tests.ramBufferSizeMB", "100"); + + // use non-test classes so RandomizedRunner isn't necessary + // System.setProperty("solr.tests.mergeScheduler", "org.apache.lucene.index.ConcurrentMergeScheduler"); + // System.setProperty("solr.directoryFactory", "solr.RAMDirectoryFactory"); + + log.info(new ConfigSetAdminRequest.List().process(miniCluster.getSolrClient()).toString()); + log + .info( + CollectionAdminRequest.ClusterStatus + .getClusterStatus() + .process(miniCluster.getSolrClient()) + .toString()); + + NamedList res = createCollection( + miniCluster.getSolrClient(), DEFAULT_COLLECTION, 4, 2, 20, CONFIG_NAME); + res.forEach(o -> log.info(o.toString())); + + miniCluster.getSolrClient().setDefaultCollection(DEFAULT_COLLECTION); + + log + .info( + CollectionAdminRequest.ClusterStatus + .getClusterStatus() + .process(miniCluster.getSolrClient()) + .toString()); + + } + + @AfterAll + public static void shutDown() throws Exception { + miniCluster.shutdown(); + FileUtils.deleteDirectory(workingDir.toFile()); + } + + protected static NamedList createCollection(CloudSolrClient client, String name, int numShards, + int replicationFactor, int maxShardsPerNode, String configName) throws Exception { + ModifiableSolrParams modParams = new ModifiableSolrParams(); + modParams.set(CoreAdminParams.ACTION, CollectionParams.CollectionAction.CREATE.name()); + modParams.set("name", name); + modParams.set("numShards", numShards); + modParams.set("replicationFactor", replicationFactor); + modParams.set("collection.configName", configName); + modParams.set("maxShardsPerNode", maxShardsPerNode); + QueryRequest request = new QueryRequest(modParams); + request.setPath("/admin/collections"); + return client.request(request); + } + +} diff --git a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java new file mode 100644 index 000000000..2d62fc0af --- /dev/null +++ b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java @@ -0,0 +1,99 @@ + +package eu.dnetlib.dhp.oa.provision; + +import java.io.IOException; +import java.net.URI; + +import org.apache.commons.io.IOUtils; +import org.apache.hadoop.io.Text; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.params.CommonParams; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.sql.SparkSession; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; + +@ExtendWith(MockitoExtension.class) +public class XmlIndexingJobTest extends SolrTest { + + protected static SparkSession spark; + + private static final Integer batchSize = 100; + + @Mock + private ISLookUpService isLookUpService; + + @Mock + private ISLookupClient isLookupClient; + + @BeforeEach + public void prepareMocks() throws ISLookUpException, IOException { + isLookupClient.setIsLookup(isLookUpService); + + int solrPort = URI.create("http://" + miniCluster.getZkClient().getZkServerAddress()).getPort(); + + Mockito + .when(isLookupClient.getDsId(Mockito.anyString())) + .thenReturn("313f0381-23b6-466f-a0b8-c72a9679ac4b_SW5kZXhEU1Jlc291cmNlcy9JbmRleERTUmVzb3VyY2VUeXBl"); + Mockito.when(isLookupClient.getZkHost()).thenReturn(String.format("127.0.0.1:%s/solr", solrPort)); + Mockito + .when(isLookupClient.getLayoutSource(Mockito.anyString())) + .thenReturn(IOUtils.toString(getClass().getResourceAsStream("fields.xml"))); + Mockito + .when(isLookupClient.getLayoutTransformer()) + .thenReturn(IOUtils.toString(getClass().getResourceAsStream("layoutToRecordTransformer.xsl"))); + } + + @BeforeAll + public static void before() { + + SparkConf conf = new SparkConf(); + conf.setAppName(XmlIndexingJobTest.class.getSimpleName()); + + conf.setMaster("local[1]"); + conf.set("spark.driver.host", "localhost"); + conf.set("hive.metastore.local", "true"); + conf.set("spark.ui.enabled", "false"); + conf.set("spark.sql.warehouse.dir", workingDir.resolve("spark").toString()); + + spark = SparkSession + .builder() + .appName(XmlIndexingJobTest.class.getSimpleName()) + .config(conf) + .getOrCreate(); + } + + @AfterAll + public static void tearDown() { + spark.stop(); + } + + @Test + public void testXmlIndexingJob() throws Exception { + + String inputPath = "src/test/resources/eu/dnetlib/dhp/oa/provision/xml"; + + long nRecord = JavaSparkContext + .fromSparkContext(spark.sparkContext()) + .sequenceFile(inputPath, Text.class, Text.class) + .count(); + + new XmlIndexingJob(spark, inputPath, FORMAT, batchSize).run(isLookupClient); + + Assertions.assertEquals(0, miniCluster.getSolrClient().commit().getStatus()); + + QueryResponse rsp = miniCluster.getSolrClient().query(new SolrQuery().add(CommonParams.Q, "*:*")); + + Assertions.assertEquals(nRecord, rsp.getResults().getNumFound()); + } + +} diff --git a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/elevate.xml b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/elevate.xml new file mode 100644 index 000000000..668332b28 --- /dev/null +++ b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/elevate.xml @@ -0,0 +1,31 @@ +Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + + + + + + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/managed-schema b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/managed-schema index b50c5586c..977e0b2d7 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/managed-schema +++ b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/managed-schema @@ -1,1003 +1,404 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - id - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + __indexrecordidentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/solrconfig.xml b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/solrconfig.xml index 562b1cb55..79f3c6104 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/solrconfig.xml +++ b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/solr/conf/testConfig/solrconfig.xml @@ -83,6 +83,7 @@ + @@ -204,7 +206,7 @@ More details on the nuances of each LockFactory... http://wiki.apache.org/lucene-java/AvailableLockFactories --> - ${solr.lock.type:single} + ${solr.lock.type:native} + + + @@ -366,14 +391,22 @@ Query section - these settings control query time things like caches ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> + 1024 + - + + explicit + AND 10 - - + + default - _text_ + __all solr.DirectSolrSpellChecker internal @@ -986,6 +1044,7 @@ string + elevate.xml @@ -1116,81 +1175,70 @@ - - - - [^\w-\.] - _ - - - - - - - yyyy-MM-dd'T'HH:mm:ss.SSSZ - yyyy-MM-dd'T'HH:mm:ss,SSSZ - yyyy-MM-dd'T'HH:mm:ss.SSS - yyyy-MM-dd'T'HH:mm:ss,SSS - yyyy-MM-dd'T'HH:mm:ssZ - yyyy-MM-dd'T'HH:mm:ss - yyyy-MM-dd'T'HH:mmZ - yyyy-MM-dd'T'HH:mm - yyyy-MM-dd HH:mm:ss.SSSZ - yyyy-MM-dd HH:mm:ss,SSSZ - yyyy-MM-dd HH:mm:ss.SSS - yyyy-MM-dd HH:mm:ss,SSS - yyyy-MM-dd HH:mm:ssZ - yyyy-MM-dd HH:mm:ss - yyyy-MM-dd HH:mmZ - yyyy-MM-dd HH:mm - yyyy-MM-dd - - - - - java.lang.String - text_general - - *_str - 256 + + + + + + [^\w-\.] + _ + + + + + + + yyyy-MM-dd'T'HH:mm:ss.SSSZ + yyyy-MM-dd'T'HH:mm:ss,SSSZ + yyyy-MM-dd'T'HH:mm:ss.SSS + yyyy-MM-dd'T'HH:mm:ss,SSS + yyyy-MM-dd'T'HH:mm:ssZ + yyyy-MM-dd'T'HH:mm:ss + yyyy-MM-dd'T'HH:mmZ + yyyy-MM-dd'T'HH:mm + yyyy-MM-dd HH:mm:ss.SSSZ + yyyy-MM-dd HH:mm:ss,SSSZ + yyyy-MM-dd HH:mm:ss.SSS + yyyy-MM-dd HH:mm:ss,SSS + yyyy-MM-dd HH:mm:ssZ + yyyy-MM-dd HH:mm:ss + yyyy-MM-dd HH:mmZ + yyyy-MM-dd HH:mm + yyyy-MM-dd + + + + strings + + java.lang.Boolean + booleans - - true - - - java.lang.Boolean - booleans - - - java.util.Date - pdates - - - java.lang.Long - java.lang.Integer - plongs - - - java.lang.Number - pdoubles - - + + java.util.Date + tdates + + + java.lang.Long + java.lang.Integer + tlongs + + + java.lang.Number + tdoubles + + - - @@ -1313,7 +1361,7 @@ - + \ No newline at end of file diff --git a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/xml/part-00000 b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/xml/part-00000 new file mode 100644 index 0000000000000000000000000000000000000000..ff4095a11b566129a3de425341f042d29717a094 GIT binary patch literal 293298 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

;*cjYxKSrFod5n{Z< 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

  • X+?t` zB@HSWBP}eY#&XFS7Kk})Lc~EtrLa`QnvoJjNMc4PFXsqP=CfhCy{y)4n(Ux|dJ1f2 zgqNfeAukS+0rUNoTK}NePe?Ys$XWRn;Spsfbg+4i2~9HFv-6dPS7?hiB_L62!Za@9Ew!2jue-8enl(QYQ8)PYs z?Uf2`0#@X&yC==FlB$dzzS0$V_>+rf4zDlFrGc#vPiKSkYxmCFetn+z)RadHYY%P% zqTUKaNdR35+FC7Gstg#zt>?Ocx#5br%{Oxc9PYgA_Q1?OH~o$|+PiU5>*B(!xG>wR zm|Ml%D&|%(w>xBRQA(nRnW9>Ivm0XeYIyA~?+)5rnLh1^st67O^R^rZPB|H)wNoFlW z(OV)gR>&nYhu~E?(xbBySL;Um@QyHcpXZ&I-IM(6NwH#bsY%%;DB;QL!h&sq1UHM7 zl#es`92>He(DK=*{dUL*Um@z_3~S9l&UVd7|Ksf0RyiC;!z(C3riS5Ei%;*h_yk4; zzP{trT3@>ye?5L`z9(qD^KZ;C5$w4B%d1gCUOCN~p~wQ4z(HH=twlm|PMw#xT7)7f z1zgkjA%cTjv0g$VcsZF`2jzFoRyTX`*(B~~Eb)|LFpW4Eg*>%N5)lQ*91+FGxnFsh zWrH!LHq;7T$9jcH_)Bjz*vdLy->f$_HwD{JH!;9VE7fSfYIgE=kp^emw9WA#BTlW~ z1MAl8Rb24VbHOUYx}t*jN(IYS%QzWte9|ebwo5O&kM5Ov13vTaO4!<_r*+JiC z2j;{;OIa-@mw4)uSNTKs>&d2%kifx#$pBE;|1$e~x;`ZYyRly%@3_=FFfuqZHHx}W z^PR@pHbM$9zIGX0e%}jN|J}myBNHhm-be#zYXg;(aZEzs99w5WVQ$Zl$|UC&{76;& z=-&8IV_m4tbzEE7+`xQ=)$72I2#_RM=M2|n12M#J;z!$|mkpeyiUB=#1_Xw9!fe=Q zU`>5Kmw5~yH3j+_3s)wjifWn%0Y*b{%cP;0QbQ;*m}zo7fyFg7pO(ksp5)}6M(4f~ zKmFr{0c;-xbsAv+?(|1Wj&PvJQDKy&e)cM96=2UZVAtxKtX`|36)kIQg<-n6QqvoB zMe|J#9E}OIA#Vcg!8XUD?$UvY0s6Y}MR5HzzgZ!8h2Rx}F9d=Uridg)FpZ7TlA>s% z(~L&uxIvL#NAPC{jd_6XStYHpq%Zn+=L|Lu*{Wd7lgjaW|{M39xS6?5~^C zv%isTgl_Y=oi*BUM+luXBlx`MD{z18;9f0I%n`OP!2*RthA@mY5}Z-)Wq^N^!$}xH z(qKQb_Zd?JZppN;k%wC{*lM@)S7|Rb+%|FLVB~_S3kZV+kXp6_1Jr_-IW4$C$PU7B zv8wWE4mKi%keHNP=GA%jycv6GM`Ih_{rlmh3HCHw&vTH(&gF8-Jug1|)jytN{`0zb z8Bvq?kD<{!DX=F#2o;#FUIii4X~mN~DZ0j;SG;G=c~99!d7~q<(P6B# zV3BAMqtaFyYhwV(8ou75}9#H0w;8TIgWZ(7LewXz?)8-d&2>|j*?z`}PLl+rv0fY!{f*;%28GL=BYI(nxI=uUF7Jk%E@R9l> zq!p$VntYx@U{Z_T17mBpi?JD+p>ljQK@12(Ign%tG=h2OiS>Z)T6<(naD-^d1P_K| zL`SUS;8;ZHnJ8!XZR87Cx{QK{%L#l+%JiT1sS_SW`Zt$vu& zsn)Xk?)LVJovp(kWb3tq#zwXeCt&13Jd)I8$=3$gVBhyl3s_FG-2{)I6Jq~3 zgzOwF{56SIshYsjNi<5dlMAjL(UftGqLxMwN~nw;@yb}=tFd;eyuy$ANni>xa?MI7 zlMEww+%c!8#RjAc`#iyXj|;TGOfR26YpSFUOjCj=7Li5at<=ma$tJ~O za4{{B7>5UO3Gm#(yRQKoH|;M{ZK14tetOo+PYY>p<*!$U{Q1;$z}NQKYxt#|eF!%< z)5jz!e`d}z5Zi;4lj!uLtluptO?Fu%EE~}Ov+lV&$yZXXFq4G57r?!37v1O6Gz(mm z6sFlpcb>JtP3;vgaTV^mHI5d9r-afE5+nXy zI>*zr>AlRQ;0CLM_QZK3tU}RpqPWHgNf#`Z314q9O{zV9x(+MYee{!utOOZEDS_8b6;z)t(I$|wW-fN|C9Gj{w54`47 zQO#4r^czCMw+{Dfo4fnj!Sh+_=QhE}z+k0XfaQ{Zx0|#b1Qk_tw(m1%d(n4Orfe@R z`C2o!jdEIrgEKI})l_XYReJ~2a15Lj14HjPyuFM}DMA>-nk(>ru(nFyObvq@WoM0g zi5jL~hd=c@U{b-+Otlr81^*f6hm99EGsMk3`N1dSk9zV14$qva;9w8m(8QA`aBe~- zg7N_}Z0ED}^~SV@o;*ocj5kNFFNklX6Zu)O1fFOt2tupaW;hIMOzYw8@cQH8B-r3A zd;t;x=RXE|n1myhfCdT%L@-V2+Gc(VLXs7Lch&&{*gn2wW(LHoeSZ2$ zRVx;Wc}l)29M@hVj7V@4h==8Y67O!68Z%Kp`rg5f7>!lQt61X*YlI7)0lWJWu1LK# zG5V2n@BuJoN=W7vrx=(cga3O;J*eJf5;>Fur6pW05xa4_!VflT^=x~0ed{^=xLGt}w87Sq+IoSS+PcB0Yz(%87LOrB~!t=T0lz7OesA5=g`85h>SDf-eIpxq~ zMG>X&*hg&OM};&qjv~Q5Q7%e~M#3H?kxJ1E?s36OHuKJF(*Z~!#ai(QU75s9wrZt8 z90n&A^K3=OjPa7A`BgMQyWj7 zydx#ofKDEqg2ZH(!&A`DE{HBjxUsEJ3JU0@v!G2Ge0k?;&h{#)#zRGPes^_YNMA6D zaux%LMA+zks&?$P3|hJnq`h6um#;NdSdqSOlJsfK5tEwG38e38b6Op~6!7?q>$}#j zh+q9#WBYJ_>$kJ@@6W&o-LS=q63#azypuV`o#!Ro+zCDCtrpnmxlG(zvBCvsg)Ujc zXmrq28AN2j45h^IhREoGz1$2liQ?^#alA{joEXKu5xzoi1QVE%a!tZow%2Usy=)J( zrFWSSY_F4pskxZK+sj+$sZ`-$C3eTO^Rp8J=;=bgNIKR{>$qu4OsknjYmk!c>Gs~# zv|$THH}|LV&HZ-}&I{6?damg05kKI*iv-Sde%3KpOLJ}w$1?3G(JAU$8U##3Q*E5F zs3MHZLKrpJDV3@$Od*UDGaQV}Bo>9$iz4)?{`}z&vc_*W>MstrzTcQ-F0mU{kMmcn z{g*d0#}Y4mFXDJ{!Ml0m#g!FpT=EntkDEDGDN-IjMaqxom>-mf7!$^+lSl?4t)Y&q z5PhVUBJMR&v&WvT-HiWhj~3gX?r&`XazAb5cC@VJRbOQr@U4mAPXhE9nL$V~i2%wC zAzr&kJ!U2{#kG`4rq7ywL~r16aAz14WWIgKD}wbS%K);K+bkIbGY=^m*`QBpln&;e|{3Oi}ohHYOvJb_F!Lo2l$ zFB>j&p-d`T`Ed?Etd;1++8CQyD^Z8Fo0!7d1U9fXGwM&ja;=QgYvYi-Hj2J$-(-EA z0gis{S(<6k3bx5LlQY`ugs@T=sueivhmRe*cqSMw8W~&u8GJ!zQ<1mOu5Il%<^_I} z3SK$GMpzRJHI6z;qvg(F9VDle1*Q!a*Wq`vem-~wy<3=pF$A8ybF?)kD4O<0GK#EZ z)Wql_BZhnBqMx;MM&A1B{Dbz}eN_`&TNn}o1l%!VL9QK(RJpYKHDDJNArXmNRQat) z$m1X(l2WP?R!k%z?SsQced;_#fz{a-NMf_s?-kRwhXCR2JcUPwZs8cz&dyqC_sp<% zR`(t3WcbkQ{A9wVgU9CCK|j@$$UB)2>G{Ru-~3(E&CauWdT0}VtifA2kjCz8+$YIS z(y-uGT_0f4hc8yoPR`asdszuk{Y5$Qv~Nwtdls7aFd_qWSUIg3K!BxOrCMSf`Dhg; zbW%~^JC%Z48=Uu6`MY33&=PZipGFI?bg(LdYta%oz6$8hcZ9Y`9N+I9FUZZ5Zt7eDL7SpE%$+y*Gc7ou!+9)DM^U&A<_d zZ!|08D<0vx#p|se1NAcl>bDZw$E&7$_QkStzjD;aU;rxix6telrxY9-3om5UGGa}G z@=gisC3A4>`ozu+>V4nRGLl4miZQqghG&@uM(3i3|4ZyJjSc}D_J*q{91e5XC8IC! zHNT#F6eL#$WCAc>MF-ts1)-QYO*Az#fBh}&{e5@TeJwoZ3&Y^7lz}7Q;6TTN#@q*^ z9I*lsFNlk?*IB9<+~Z(yNx9J~yJ606_h1(PyKrYm%1lGw>~-?qKv3Q>!Iz#e^9)?x zT?J`gJ!>uNtlM5WHheEnD?SzTT4?6wV&I-R!Z}sIy0i>5AS_8>g-s?Od_9$$MWyds z&fb5yQ6O!DHB2$Ds6tAnKnaXx6w<(-3CoS&#P^Mi&*kIqb!($4K0EZS% zD-nbd9EY@Ki~}H_n0@bD#W?PTaZGw@GMF2?wf%`z5~K?{=*Xh+Oaw`RHbx{E*1;KL z?N~f?y4mNZGr0M4^D-Z)kWh|_esJ!?7@=y_Pv$=9RkP7oy_pA1zI1Ta6-`-NBA)VT zIWNtp=FHq}o~(+d+{b>l``f;j8UUETeDg^=*V4;&K|fr$zIpBH+y`SO#c3QUQ`CV) z(g<g7WbADl1musiG9?iG4JdD0y6zd~ilBx&RfAjQQ!Q{Ft8$Ke9x)K?z8E?M^? zlfY!#H}YUG?xPouePX{k-yeCyUbbn}wJeuJaVZoQY1&XY0)&-2q`dTzYb+U>wB&iW zW^*=xdT(y7gp(3jxDEu|mVlKr!bib4SD0{P=H&x#i|hA9+5gqQI>(ef0$U#$S*$q6 zIBKOVbKa#{a6-A#oNyE|dyiu5{JnQCqGjB@xS6+oH~X^R$u{5oX-etRFEUkkvd^2{ zZfK`O&#~8P!b93A?F;-47ffR7+%p+jDnute(-=iZw4_uyi4}2#jIs5y90Z0OCB`}C zEee_hA{0YdS|PXzINp@{>{7el{BbXP+A&{(2XkS$v-swhova1~A#dlW&8l?!qu-ZU zJ1p7!8j#IS^KO@mtHQ3!n#-bWu(-8~5C`7^KQM-^aR?J10mQHgnvP^R+siN(oKLIl zT5fyu^UYFPhvN5=NVhK{_p(iBB>NDq_-H)811Q6d`5hX~_LremeA>%i82>hC?a7n9 z8S1+3o#ee7;INbG0R*5rpx@nofe=|YZLLYzah7D~h5@*}y0vG&)%mA6625mEaTM2+!ss*<8h3lrZiI&?5F?d)mjn$zB8$4<>U^3d`LgtGJIPtytD zr+dRnFB8S|)2U**G%{kS2uAQgD6`5q>X}C(RbFIFipYlv7l$eQk^qco+MtqOv)2VL z7y7WsMRSqSrnq+HFm+uqu&vRRpmOmKFmqIJ`l!s@(#Q`ZL||^Plip+Ig#+h{E3SP& z1YeeL8w~g1>wLvGK>)ggxsmP}Gzf3+^0V_{RXq@zX2OM{#&D9OZogfYmi;VcDw!iu z>AY^XS4wtg|IIJm%a`G#b2iNY?Nbg+P?x9y~u3Tng<|j8YVo*Y3Ij+DtG6 zCdcK+?Pft~i=7F>BBXN#M_=2HTo_1B8C!zdW99zwj0WSaKo)B&z2=+*MZz#hHHcES7gU}HnaTs4xW zRz{n@#Xi8i)pV_98}3_8WxUKPz)5U{FV@`Y+L<{H-L->M!gc-m?s}0H;`!Rv;o8>5 zUQwBK4KHc1`c`@2XA6e!;S1ZmI}hdJL)Pr6C5^%^aAq+{%fALY;tNx) z<8Fs>ZjH%3g?;?mJcoUZC27FK5T%)j-sl*m#!BgweAIJp1+^6oSTY(wxS(n^Or`-l zNwd6*WfTFByK?Oox*x6$I@ zfQnqf|FAL%p zUT41(Ofp&1ox4H9v-)fu+x{}uJ?O2rzg${u_?OC`n-zX3f9V3k6=mYnav0pA@pO()!T}6|PeXR)^l07vq`_1-@ z`30umGST!8$H^S`SB+c!Vail~+-i1DmK6c+Jt0Bm1l`sNiir(VPK6TI04b)_NzELN zVC961=!4s;z(eddeh)pquZ5+5eQ^L1hBNIXMga+~4dpyC8@O`7ObL-y+~BeSB#0Ce zHv!~!@Tm~<)tA;m3th97Ju{uxp*3|)czeGNT{UA1(}45DbXHG0E`ewN<+6h2d{q>! z+^5^1!~eH9=nxfQm^y`U&|Lc{qBV*|sW}N=Rm)4uh7L>!!B^>Ibl7+{wVK>c;~DhE z)kV{6ybmY+QF^La!z8*XQ&&k7v0F;!bhUk28vQCXv#!DF>M5moH6N~#=>1+ zD4I<_Ld(2P8~vVLDnLpj(?5Mgg&4p6Vqp+a8RLi`OlgfJMVfIhkO(>oOTCfR1mcn* zAV)l{7KzCS_~Pl_;nvi^*fYSU>}e;MUbfc)Q`F50SxCE12R7$2i}dt}i{X>r8FFzk zsQu%!Ub8~dg+bEAcb8^IQmj$nJmmvY+7aeK!8vlqIzgmS+I(;q8Z?`xE;z2fUL0JF z0$auc_?3|e%{e8=8)qXxtWvhZ)g{AKhBZ+)dX@*zYKObiaP{qf{q`Te{n=MPdHajE zKYjZ@z~4WA`-`uB7k>Wpw?F;r$8Ud{z5P$${t8a~IUN2;`t|4Ouit zHrJGFZ8fLDged<;HMl~DY$WWs9e(k{sxnAUn_pUu`tMMf|E8<;T%)Q zFr+AAjz?>d#F5gf%-FIaFHhmkt9CN-eg@0gR=;(DQuHpo%X(*M@Glky4IGlfFiwR=Bm_kW;*oQ2J-1Q_6)QAYGBjYE zOLUvR|$~$^U z?+8hbfDuy@v4$T#L!hP7>c}X!I-u)|dy`e;-bZ^x_f86x$aaQ8njM17w~Jt_*~-h@ z5&HfAaic2}b@&bd|NsC0DVb)6UUl}k-MQUGx7k%!jsc7sABzY80000000T2J8U=#| z007W1GJ%W%00535IvOtf=jjjTaxi5)C`{4ff-~Rk#{r>gOZ@+Dey{A%rpXbcFdUqCcFKy=If;s;h zal+Ya9`9<|dxcrb_TKliPxCIK?lv=9GanxdrS}Er|TDJZk(R~{ujS|KvzOS;{D9ia(PRhH5`i%J7`Sls?B=1-3 zDTFwZKRdL^=Vnf;w(z{wU;lgmSO4SB{k2xh*BM9btIfG<;`PEFi3OZ~tX?$Y&-p+9 z@#{0pyA}G})^aGa60RjT-HkX8cTbR*s;{P^7b)X zv+Y}Gp$zAm#d6G^ng6-t>VNNFBZf;ejFwh9`B*8@mosM0jnDh(o|(_T{<-=;pHV{R zUFym6xY1%d#7D|24tB7$5Z@zCn01)h;??sh)AeO0pa>(bfHXL~{PLm1Byz)w5eyWW`inWES)6_lUXIIBpT8gZFEG5i>65 zG<#&d@_dijCAzYDiZi;?$BB8lKFJH;TpBTH#McToZp@Ezy0R(Op9&kXN79R zosn843{z^U5fASXVb3&jiEKDq5rXS6)Kq+|q3u5Adjubh)BCZP;$j~+Ns*Yh>#nuY z>wCo9W9{LVZ`E1p=lGTO9@Du!3XAp5bLXpTVJ=%?#FAVrVY)(wM;CTl>oS5sET!=g zH&c46BoWli?Y`CNUPCq+$+0nK#1bs`&0(`@8f#}QJ4cb(2nbawaIm+cn*qN^ZdDlFOXyM%1>vV+9*KC$pNBnF@c;*b{xRIwX#&&!C`$%?#Z zi9o+k>|z5PSn+T`cz+qOViG-}^3eMUIxd1BdH0$v)kHPCd>pMzk zQ>^FQTW1aOIq>IrkC=-EWMQGs5qBhxX9=s4XbDDfmuIl<%bQ!<@ekYSW2+$J0lN9) za+wF&(U=9v(PP{vc-IzR&+7?{e7P{E1DhsMWr4j&ir4VO8Sm`-`^+- z^i7ag37Co{rfp#tz9jd)*4pn83Fh4y-a+a_8>k;5L z9NE$hq4W?gZ$;=1xXi(^=qwMePok@I__VX-_8!sAZ^8*0&YSQ$b_}pa%xwiiij{^$N1^QefA0-!HM7Rk%n8QR8Th2vto zWUV`hwGxP5rnx(eWza%A(aqjlxUhj|pPdKwI~0}z#8Xzaz<`FVOP3L$EQ4iZF37jF zSk=OdE=V`7kisRSLU(W)fewGTdVq!vcM@h{qejmKshKfA)!ka)x<8?<4uKH7ke!R} zGV_>F+x1K)03eb_L?+6{8<0Cltjh>0lmp7w zLcFJv*}xEkn~34}2v`MPJ*T?U$~?B%luR6;1_Kki%!8O~8_X)mB{W=;A|b3&LlX1i7VIx()xTcJQLr|wM=>n#wunPo;=VLs-(>^YLev(V` z{WhXGb|hlA45k#GhOC*T$VB3}IF=3>1gmSI2`7};Cb0I<`|M=Fevdc>4}e4;Zh)H( za6^1ABs2V+hMO0Uvtc8D3Mc}Wh8TgCp4=>!dEJk`(g&#$;T=%P*V9v4|7q!!sh z#`D~5#OTEp^`O7NpRGO508g?ThDccS83g&+j`g~*0jkO&akth-8$3hB6=!PT93cj4nenh(3za(k1>0*tJI{GmZ_^UV5^;@|1(7?j?H4xKVBdke2S7^} z8cgkRUTaKt{!=yhK0^K`+qMj{Swmp$0k4HJk%I)nMYnr-OfWVe?a2)IFpx2}+u7{t z4dKFeC5^F*@6e7H@81z-X$?mOZPr zi_%Bq<=UEp4okWL>|%CC2oaBZ;)T^PYPF+~WLFL*#2O1qS|xU#kiM+dif320>p*RR ze8t+6?ggcY`d^<&{Hb0+n2cF=DF(vHs`!HkgkebL`c{?z1|jFMj3pdsU=?>f`wiY# zn0>qvE}#=piII@Y2qg3aWKJT(vZ?-A=D87jte@MfW4j&L9g zJK_?r>o0X5%qjfh94v@WZyRG!A!Sq}riwtjU}CohcQId3u`^$D?cfs{UrYmov%3;VK zizHWtA^aPu@%(X--I*MO5S-J53%oFD+UrwW`mXc`FJa`tB6oYiitK}L@rbv?8l+z< zMPDO)P}R-5f<=pDcXn*SNpXuy!v}qSj7Z1>ZC{OnuLR*R1u>v+%F6A-INwKLgNsAN z5vQbYG?+?8p@$iOq4VoAzWC!H6CIW@Yq|-p$!Pt^*C4#ySB>mD?m7p5x5WY^{^tmO zsDJnk$)ywLrG6C~+S1{k5xTqDWEu+@M97>4K(tFW3h}kWM(V`clKeraqzKc)>dky% z9OTztQoM{PMa5BqpU=S_5L>%AmIFw;gUgHrRPYFyRUoZ_zeAUl%QMc51yQ^=R#2+{ zV1T8<$Eb}oS#QTOnj<-|5Lj(g#f}wWlEzjQV6^bW)%nM-SzEB1C&HgtK}GvGrzv5; zuac(SDqbCugj3<#4m=${a0#{Z|B)@ac>_4IqE%O9vKyhKz(3ogVpuZ{(TNq9?y z1L_Q?4N}xah*&1PF02-M+g@Nkj$@H>^_W#LA>mBmU7i82GCe2^$P7Sq^%!8uxEfWK zy098vpymaJAd*&8HHu(Yb%UtH8D03?0>Ypo+#p;O2BFp9DFQ#@wOhYA7C2@S)Us;q zG+Plnk35@sfz%h3foEz&{DM4LF7L6cuC?Y+zrgRUI#?qM1pHJIb*uK6Y(Y}hWi&*- zsSF|)UxITADrAYD0jWxcMKmqRei>2c@nlDj7WV)O=7Vp6{|wXLR0h0U-OvVagg}49 z;Q`{ZPC)SX7X{FWaJGx7V{w&R6=csK99)IBxQ*yAaRhcpJ}3ngCX#ERHsKYQFK;DL ziTmaAk-g}JXo8y|P~zDGt{0WzoGMk$Qced_YXg1NW_AVP3yR%ziA=DeD9}C`_1S=_ z0NCd}P?LL;Dtl-_#lDFb85@ap5HpD+ z{N&)@&L6+L)dWjK_v{-`KClPqq=gY(s8jbi@t@2|kUBjbtO0slTf7{`v#3ava(ItO z5=QV~Aar-oIbRyn5Y{@IKw@8b(4NDZt^-26WCwPkLFpy<&3{faevHt0)TogD;0wXv zj;RZ?G1et;;XPtcmIvq1F|=8jE-B{8|rQ9;nUgA@de%0Ynd&gjCkIx({ zkghf1pNL)}#$T|+Ep!1k6Y#*Bqt;PdqYz)UrwG7bc(9d;se#-gD_qPC6-pxzFT-#< zk0NpwbAbCiGL(h#gnN$;7e(}>3$_RJM_4f5B+AjbXjrl%Ce(5q($<&C9Yk@SS{Qk~ zQr#&a0DyS-LFSUkxJdx z64vSn@~C!xW6mX!I`@g>YY(cr`^Vq|+-tNOM~$v(_OY|fj1{mr;8&AEw75lI|5L*V8*f0h<&^9lF zT+h5!?)J(#85zyQ*K>SI_=bp`z_8~})%iOcF!2sLH6nO|@`op&$4J9r&L4O4wFg6l z!G>G6?>Lk;bkc2@wNTF2InH-qE40WmcnvMGSlUvDj#m)asec^(50}~v6|!r_YsQ3J zc&d(@Sq0wE@3-?JF`@9{b=Zs-j)qHOOQ3V-lWUg|!3=)~kdQw#B%91 z$f&PU+XflOvK_mWxX!_lAGq#|kE%06luTXJJnZ;LFhih8?HsMHw~xZN&lHNRAPguS z?b(r%f~o$z`g;WY+YEj}UhsZkEpV0HqdHa{x9XryPSNcJ42ghuGwTaQ70)cwKkwQaOtkin}&nr2Yj$$@C?9XPIdH9E4it{(Txp& zOxfx%(Z}eZ6_DO6>eI}E4ZZk}1~LJ-6TpEAg526>*#wXi&watf(8%snJZfyB0J7{5 z(hr*NsxMs-&P#n0c3H=+J6I+!I*XAip*C(O4elU8UBcw;i6VcroQv3C_6g;6L7#+r zLrgb9(vSi~4a#*GxK1!G_r{VAag#)G1Yp-xLr6zOUNj*3WVm;pySbs4o>2;h74A`| z^(SGd5G%7>P8x!tkHF=vLkh#QvU1^}kqn=^3;G}mor@s|-O>{+4%GwJw;qrW`+d?t znDf`{RzbHw9rLv1u?d*=W#iMm^IeO2q&-4x4e$qx-f;Cv6(7K4^6*Q=3(O%02R1wQ zC-{&;Lq+AG)AZQiBbEwvG7z3sMl6gxA~K$Ju#SHCbZmX=rm7L(bgky5!^Gk?Ggup> z>?orAsp5RcMD&Y{YAlJb2S2tBeBA+YGj{r;8NQEToeXS8*Vm2W2%SX+RgT9SWuG4Y z=>PHmi1^Xe5EM$)dCyly3FgS6$s(4r@&$J*X@{xrm5i;C(C~|;$n0r4&tJVpj8lrr zn=2wEk*+$MQh(S$_{~}_&*0CIDC`vftCEJbUSMdmO)BEN8+<`UobC9oAD(@>|d9pz{W)-&HBM_0Z z4b?0X$Tpquw;tHG4pmVu&uE_={+wZTSS|P27t%(3DPLVLKh9WyhDj=bBr{DvJ#^)t zl0j8h*zJsd>9`mv?lN{YK$X48=#pF>&2?pi6UIVxx>O@Chj8mpfs+@Lba;^!y5T3*nk?+iax0`7wCSYS+`GzB^qp#hmW($?Hj&FjJj5iw8tp-0gUX^zNhoz4D} zEuo$ZQbS%Yg{U)=bAS;18W|at7!BWcd8>H*891+S9FrdpO7l8+TJTNnpl{tC12S>u zk+70v69m0j=sF6@G?xpuXSttR3)Tpc)u*J02NJ@mUCnqG#;L$Qh;G4kr@n`|u$quA zbYSLh)u`GXK^u@1#E{@b0uZkRN2i=GwZ00^pM^27(cHjb6=RV9Tkc~)4t$i@wPyi@lJE^ zc1-0^rFWOm4Dr{douR9xrNY&iVi3gRkvm|rcHjVOs1Zvfz^vW^95 zp3ozhqHXCzV#+=U_k9GKO6mwpztzt=GyaCBA%<3rr;H1q=cYEe8Blxm)4z0PL{l2m zTH(UZ2r;6;tDn=c_lR6!+fWUN#*7`YV5?-4PmyEaU+H=$p%daD8V z?a2|}Z~lYj?`W{CQhC`S?WW^t#G>jk*)HADb-5a5_5#h~aM=jngFqn({V8^FMLhhZ zf}3*4==?No?Vv8;s&2}7;V6$!biK&Wk|v4iLg{s{ss^jmE;TaZP)-}GTuE3`)njW1 z%Y_)+fW~D6!Ywl4C4nN>ws{^cP5EvbR{a@t1$z1 zjw(5Y%Sqe_jcJzFmru+ct})&*<0OYeNnQ2>^E=q|$r@oe)x_GYsWi0`*0Nmq{A_}- zp~R+6x$vc<0;5j-3=<)+-xWxdXvl_lf*4OTSbHf%Z%et*RPiM~>@kQAbCsFZAxMyUlQ&tS{c6NX8%( z**?AoDrh5KYGge$c0KZHrY%1KsMZrgFO$5woPYQtQSY&7j@Z>P5Nt!nYHE1mOJ7D~ zRf=vN)u{_c@GKt;sM!&q>3(5OI2j>|D%^_rD8ZD~0jS#)J%48YqgO4d3(BG5#xQI# z-X)=vk>jagc`s)yz)Log*6$|9sp=N zoY<=dPeGh$H(uL90zfoIw_xV2a)-j3Z18~8m#%3+zGoo$U}&P@c8=qCHt2)`L$rDw zmsH(#nhVvmXMHnHC)d>Oh+PA*Jg|1~n;80j41aOypj+@>-o1~K2*{(WHZ%3A^3Aky zE>$&@7$R=~(E0G`T&6a`qAHpE*{#dMI{uG93<&(##W;`;4hGS{%U+Ngd2GTr6ay;^ zqgxsoOze169e7_j3N?xE^{h`C6}^y=W!T^fN6%|t20%j~Vz~e_ua0GlIwXVUkx^q` zIBMuxShI9g=FwT*nY{|~&|0av3v*7dKH|JpZX_E6>{-)Od^8-}?OxG35udo!Yu+5M zk}+JKG-C#U%dG=~VJYzpEQE6^2_ETKtmARrvfb_#EhxvH5-QU$w-Q9*r%2ax?v|^6cQ0Vp01sMVXwoQAf}O%A%F{rWc5Wj&?4PjYOEN>e%2i7A#RdRr8W{#Wkw{F9UKz1x<#T>MR(@|?DiGhUG?URdx%rMzH2W7Uq{>4Ad zH3g0$ylxd?Hi8!;7)v8T;!?dgVc8dCN2*`esufcDupD2-XVbQ_HLGIq6z!s(JD4I%~O%AYMIE zDX9Dgp5r>_X#{?UJG;BMZ7|2rgDy7W$mg-=K`xrwaTg_nuJA$MaS zW+yAQEPnM_en0a9NXF_Dd_E{XA{l3>F0`!cV*AqlIVMkzLk-l&pt3?X>AL8uIv4Mk z6RZhfWxbjX@dt5Sbq4~t?~Pac^zVM}fMBbu%LOA?U}G`A`keTN2H>?%&-V8b$PYEI zDzVd>AFHbb0N8?wN{J0-w?Q^)>6GB>Tlb9i4 zi;jxsCkKDt;nhc^2b0ACPH$Uo9lRdH0qaZEIkGSb8K#>{briMEjcq!XEPnJ^ zb`l%A>~tiX&As<@^7>N&qgq={xj^WtZ4 zTQRq_6V4+)8qm9o+eVNP?s=+F}wQ@{pqkeQVDHHPu<#dxX3xq%^SFXv7JZ;BYnu$9Lptyy&a7R?>x_QpeQIhRPNa0{AXq zxY|Vl#2DNHpPPDJtnN~Ey0S6tScW<;3Lt^b2cD1ua=Ha~)b%@b)v37p<>txWvmZaYUPuKXJZsN&m4O7d z+5udM9>TiaKFhk)2wP&WjYzbjE4i+tl{MnRgSsOO60$3E_7RgK&!fqSGAi3`1g2TX zLgB>jvToUW9V?Qz6P;KtxEnD(4pA6~ZbX{wGw!ZoMrzUd+GRvjPqQN((3sejpsPDw zh)>jyTlE~Ngc~Bamo6{42(C-uZ>#g*3omQc)Zg6}uXaM{#CqY2r|!i=(_g=~@MDB- zmElZsTbBpH z6l6~=fZgTp>r@+QXy^27X%{siF>ff^6ZbJ)9Awrt58QQD*+dm|unlKU98}eJFQ>1A z2l$|7S^sqI5WzTZT?HWr%r2GG4Nzkytj8@1;Aw*>D}jKCq1(j|#+EZ80CMtTo|Jng zSINrhz{hyGgJo*f9y-}hC$1`l^Z-)EEKS|Rx{ScZ7PdnF7kLIcxm2iJzmH(K#Z#_INDum$U0K-9WvfdH!@-q z_ja}7v)Jui)~YTRw9Mjt);8vK@WMLj9M~#mqq>G#Ncsf~gx!j_ zd%~!(R^S2MTO!0&z>^2wI@TaRFN~v`OK#(21E}cKI@c#M2vOSAnw&2+OI_`26@!Ur zRU>%jYb&fm+ ziJ>MY*kiItnNx|I;mR={;{1NfXKNVim0e9`Jw>yvqXrc zv|NklU@0c5#yJREeZ1?!gU_#ZxY6`mJF3kLUC@^RAkec;``;so+;((U7S>VQ2>LG; zc5x6~tKXinGIE=pc#xk|8oF|zYcif3zTKn8hwCR{YS+&j8Ty{tW@T?}DBn-LwI9{%jFE6#aO0(G(ht0IRHMjnGWSCcQoR;E0Kd1cd)*+0l&a~XsRN<= z%x=^lmKGp4wP;{g*~7ys9=k9OyWQjA6`X#l2Q$LT9_*?*17#8}9>?Rz2U(V~Sg&*X(!~GvC_cBsgO#lFn16v=92mk;8 z000039g}-#S7jK-%X!}Cd7rcM+s{pwGb>Ctyp)-viwV&}F{(*gdFc;X7YiaI2)ZpH z$OH>M&Jr|&ti=9_uK!fng+lB?MOvDxSevZSiR)^cyR_ctz~OMt%X^;pd%oY#7rBBk zfu3f{GMcW(u0k%whRJV00E0k$zrUw=7+Z-wP5hN&4%&gvLcc&iAbyQ*MV1gE*`J7z z^&+ige-VZd^DAsd=93MP4U~IYkh_tUgc0OTbb>i;#2WNd^b{BFquRlW$>OteSPSu9UqYOT)nEgh`?yD-2QkBz5|c>0rWTnArL^x{EkW@eMML-RwVGe2G=jN!S{!nfi-qSdW}Qo{|D#*oQt!JWNbM^rA=5 z-N^aKH7+#;EeqU%5|tS=zU+orjupgl;xu#+J%p~qmQkr< zv#|THRm2P(AhuCFk3NWQLX)fAR6DVD;*k>j)ntQ6H`0M@DRJr{q?J9cC*MxkLEMB4 z($MQr$$oEv-s&5Q4a5;w62C&9!qgeo7tmMHE@Up@Jf|z1a?*5piP^leAoWOMV;5OM zu7*%k7H6%8n2i!Pcqj>;__5E7C()y2E4wHv*kWq?oGzIlo+f^TE%3I=8SD;<^&YED zcfmSTI=LFTjqDh*m9P*wK$wi2jVxsTO~^aM-;l#-Kl$xg>iBEkO8dnhYz5YjRhaf1 zcA0;hw@~{!aSXY|k&s$s71HS;h5=-`mp$~B@y+%s$m zGeWQuFGxJN60xU`)R}4bOKx?oq9UWJ;&k4~$m%|4q*cnUncfu{9>k@ptDkmR2?T-> zE3v@LfY2_m=ty&<5yQhU%xWGQ@xU7oJg$(?^jr`Z34vBfi^Ojp5t$K@kx^OIl~s`y zUVW)dcQbQ$v;Y6U@Bi&Lv)}p=d(aE6==q26cYoL(WM5yjJN+Hs%Rk#V9}K!X+uJW+ zzTAS}UxeOfFLaB3J}7#xw!(0`V=h9!Yh2id+Z*GWU-xHgzNA}4?`)eOgtvdbzt?i- z;lga@o&LadT-bQ{;5--~dJi8!8#{&ls_8>#kjES@o%M2mI{ve>69hGeNrjDz(J5~X z5|kUM9gm0z^kDmX3uU9;48mco7wvX%gS_Z$PhURinNB|zy$dtGwLN*Ci!d-y#yosb zn7EUg9K0HTBV4%r#>-CFD!QR#@?JU2R+b9%$9*?_Z`9B> z-a@I^Cj7nib>DA{-VS=$bn=hSTdemndPmY_r*=F{nU0Bo3jzd3~ zo;%O3`YPLnZ?&c$HnQA*wlR71sPAKB1|h{HqF5V3ympa#%uHm8YbiING(WQ3t^v_CofolcXF3{MESb zsG4by3%>{lY1~GQU%UF?Ww1~;414W|Qwor~;b!o|QVSkzPnCJlF3t-00s1bu@^QBC zudaUU!mE@b8C<96bbCe22jy?Q@#syDdU@kKKRXZ5QA2liEua3<=^F43<-O1!^p}?` z?}l`@+spf*{I!1(UYK^Cl*o@>aX9F^!l%2g7;na)`ol&pV#O(I5B z^Mw*|buVc!NGr%i@$kV!Iv$q7@nHM%_Xj?-1H7JnRbC2UZXOPLLnyM~#sj$1A3Q`` z8b8<`{ruqaF7*8icoX<3$@%3krZgv4pZVhY8g<}N)b<8 z#8Ud`EcF^~yq~drOSQa>#&6GB#_g+K+P-c#x33I6{BmXgw@1)e{!n7&Z~gF}+#A@8 zBnA(oij)k&6DMWB7@G*AjuBU(g3UF9O`+h=7Fi6NPg_r0%W!k*{^-_X%sVgIuln7* zmk$yo!AllJd&?CU>k5F+TCigpML7u? z2}PWU&XXvOaGEnEZVi7A3BqC%$xTc~b*>e-5gt=jwTbj5rqfmD3Vo~)deD3d2zoFf zbxjzFrIxw60_zX3Mg zH3*N(EcHau>>onj8kPI6`uRl{uxiKkihlp4X+Iy^m0mc@`_M}>o$}Q5Ucg8Pe}|9_ z|G&miv-0yk+gSANV?I0k(VuN>Wb? zg(rOl*6kEt-HbmzQSHw*#y2+RtPm!MDHI*CoC~VC(GE$2ImZYb@8o(7pgZ8b+Tr2j zMt&#!&)HBYx)m)gjAU(7qJ*!T7 z9yj+N9fMAto;+GbgN>A0m+XzBE-rPE1EujfD1P1H+2A~Ycm*>6Ssi4i<3VuXQJqo1EM|ZN{Y!p1VpeM)qMRy>BoD|D zZ4h#ta1|K!N>YnV43&t!nTWD05oHTR^ov;$ZC)4AlNk{`szh{012@Fr`*4I*Y`3j|_XxQ@ovHg@|=bL~4yBLfFcR zzJV3RGeD1P_AorU$>l*d!n=iPApsk-XauUk9Jn&)eqWmCsGK zo13!^w3NFmmNe~NVTOd7a;5jK?QbJSiz0J zSHg>q%IzOlK*s2O;nGLk~pstmqWI z-gyyBxF)8_rV=n9cpb&mJIn*-5j$i<6dE}txF?7q?>*+C64MnU0epr8u(cCd2L3ez zZ^MLOQpz;=9nyLqjWrT;>sCo%4Zo{`yT!}owP$Im)LAciw%L9T zG7#It9C{&p)Gi92)u6vXLi$o@=QuUPICkerWSi@7$MX$3{so|UBq$bl_qbt21l3EA#b$?XF=6< znMr9qo}Ni*xqLKRSb&O@7Z=T=crUbN26IfE_5lV_L=y=^OnHNYnx99R8S~GJ_J!$m zPUrvZo5A2byqx@6yJ?)Zg%8gj7u3hMv(f$S8|ddu zH$%Ny`k8*8qo0cq>GtGv7ci?FmO&^<+h{a$chzuze(d2Tc6J^$54R6%y9>zU>;-)J zoELe2oHaA`jAkeHOyZO-ZCA4FNuwWjA2sJ6iKqGM9W%!tZLKhKoTVVaW96u&#%t$- zVniwuEThIaY`u|h#2i)1!68)+&W+4*iiyn*1GqpP!h}Xr(Vd;gNkv`$?H>R;OQfLQ zHa&CW3Zun^D=znObGh2_4BpgwXGsw{W(7Ap`M8%^e~+C}47lu`VI4gX4dMw8g2x~< z@Ln5{5gTu&=kGyA?r6J{U;lqr7%+Qo_I<|6>wL)(?zOg8#Fx&ib zJz3SMpu*_FViR0i;Mr)xlSem46Ple)@gjv1pxVRhkKNgsD)9O_eaQ)BVh!dlXL~A0 z#i^r_2CHQ-3`LZ(?<8Zv2kXhrbC>sUphseRbbPpfc+$u=vzmXA#>8jcyc;s;vb+Q3 zvH`$UXA}m!Fr8sEWxU8|C41wy!8}MR_aATT$M3PkD^vff6H~&=hQ$kQ#XgW=*AS_L;I% zJ2P+vFurU*hI>nbYQsUX3%$RSH9E$&6Yc32F3ooOyhQbMCGSiTpmYHsqBrW}bPvo< z7k&&G3|d;eUO)Vzxx0yV1|#OfMeerNA#rtfEU1apI~^H!UKz!aGeiq-Y*1KhhNk_g z3DTvp*lan|>3~$#nmbvt(d~Ag;;dPIVa`HkCV9gBQJ!#`J$(_*bAUD|-S3V#&qwK) zVZSC8wWp(MMBN*@F;%e^*O<9-$g1(Pq_eZ&w~1UV;y46HWzw<{ ztqFG|D(M(vKt_>5FsfpnVd2JwoeUQ>;79B*WTm%$@-kz&LbXRpe^L$kp9(snkI3uLgDzjY==u zFNQrAt~05tdmD2W(P`(Iv|3_{6&BIQw7(SN3@MDc9&dwkReyFhLArhg<2yUU&ht+3 zvNJO<*KGRS@JzioG+yS=FO=ZL<&w1@<3lpH@Y!Pqx70o96obsXFnQb9c3AR8_30+} z5}{i9Vhf6I&v)K1U$yRwF;DT>5_68jWdQJ`S9FW683Os8dj~+t={mQIx!yTkWY$@`_rOnZtpg4k^l;A>Jti0Ds z<2dJd%?>=6QGyxca;b;)lk+$hMUjI$z5KJY)2PqHkkhZ@pN7E9fv0CchA#4c zT7NtrL2f*|IfDH7NNzlwf7H$nT)y?P=hhLvp^2RxxVK;}^XvsOZs+9aWLY~qJ5XT0 zF)|&{HZatkR~HYPt)p7K@nC!M`wffV>qj#JpV)%2X_Yt-qiiyqQ^FrydY2_D;1?Cx zp6mup8BJ*z)3XlwC?6p`ZnO{E=s<>}5;efM^@Go9dC&Ds9AtH4^G??2yvX6B((Xj> z>r94U|2OXqp^U^SD}?ZzNFJp_#z#yvuo7&z4z?ncA1k5MGM)A+$WlUCuN^Jpk8r#7 z?4(hDn(dwJ-hwbX)9nva(tgDmSDG_UihM81*xZ`|i)O!Pu7VR4W2_kCJ7bK-W9+d- z)(~TZK!i&!h4YAGOO=(AgoZ_wX1_i&BCTOJebDHbr?it$ntd#{7y?TSG}9*zRdmaP zpNg1GOa@q>?2~;1vYORFbHh*H1q-_86qhccru5bn_o#7rwAWbH)XvVR%u=E|B7V=> z(8K+-BT|-R_(fjs_6ssyfVd}YYL^!Vrgs(w=_lVCp23*66Hgm$H8mJs03K&9wA)#? z=$V;p-Z5`QWoUb37AK7QpmuP0ba-5D#W}^Z@0f}H+W)fpO!Pd_KXCg3b1Y)TqZdpY zsx5a!GQkPQCK~+ym?(ySWyM5qV4_gqDKN%wphW7eg=w^$2dgn<3KYRBPBE}i2LE_T zJ(BZjw6k)cv6fnBxrmsS+_LqHgWYDmc9QKjT3Ms^?B`h{{haOnq}FQHng`8RtFhlW zILT^zEpTeH{livcFPVqe($l^VW-In?CZ;pA^R0Mkl@0RYvq2uuZjnu}r{^}=TAkI;w3G{p@vmDexVdg}B8Vvy)6Mavv!L;b#aoX^| za&Jf;LpW;BDWhDg7_=cyMBoXCVuxHh4!$CJYeDh|NP;9xEsZ`NH(E!{gTv!&dCu_l zV#`QgS__+Zie43hTy3uRPGXP;hcl-Bpy<6ct2t|3QN8<3^*kXCOR22E%5cM|mzvq= zEjE<0$=RJFVv_d!&O5^tN7~Iz_q=D$F0%cilR!De8xyg)0NsYSai-mVm6d19k783P zdk=nFzO~oAqJypd#^%E5@G&7Q?=Pi<6KV{dxu2qOQ?uBKS!1QCTE46M=pAMP!TXK0 zUVnV9P1Y?JvEg^i2-iR@G%~?67KCw@d1638SR_~rCZe^Gj@07D0lb~QK;Pb4U2YzK z^7`>7?`r%%3Z*5lQChN8X-B##6cOlsZ5i=5?v0=1fF?xbxeAszrLngudcc`86luX- zxuW^tyvq`I;JZ(PR|LH9}tMmN)VyjcEM)-VE^0pq;r2NP0 zP`#Vr`D%DnuRny~<94XN#~}oa8H9;sfFyzvA_V;8kTSwbqMV2uZ(|VNtwFkLp}V6~ z4St;68-5WaMbd+p>L`i^csTdSIFWLo5VMq3{9;Y`1=E~x#Fj5BdeV6Gn~f~xc^)+D zwY@2|UPdM+wLU*+PFaFRt9c75aW)ukfz{d?tjJ`1#U}2CO`Ob5#h(m&&qKu~?h%{7 zgmG=K6h>MVoF)o0sRK(m61A8;(&$OB--PTWZQ5QQ^Y^TifDn}X)iN^iq8>ckf4{;MVQyr(V?JPQq9;mN6fM(AM#dO`h8DNa$J@S{0&IV@@c!huxeMU^q+M7L z^hZ@{32x}Iv?1&LaI#Ns`KyyQg*Dg|znTbqsEoG9>Ztkz7KRs@Cfo6GO-eTlF zt*l=t{ZsemL(&h=db!_X3^BpB#Di@pdQC||-_C}E?A!m~n?-uPkRL3sGAeD_W5jw9 z4$=_LR{Hiop41Bc{K59M!Z(nMLD@zDEsQzF_B_pK7iR_husuUKw&(c8_6(WWzKJ_* zFW?8;wCt6y3x>;;r^pU^A#9dbY!mMK@nh!- z-wK+`MrN0)>`wpu_}<9^z$kTZ-D>Ppks8NMI^CMUQ_KPw@Mpi!p7Sx z?_JB!4aQ+k&!_Ce98AAKCk09oSXT+2F!q>>D6|EC2|$l2W9`P9TB=p;(z_xu|INK2 zG9)-=xuldU7;i$5p#-26Q$=(z_V#lr6_NQkhzypRu`Rop$Qe0p$}i5hR)>=Yf5?QznI;I=~WkqMMZh;HRWMk1`?@B&3PJ-B}3MAr!1cX^BWh=GKbLDWs|1ii^qIA((ft6ORkvI-O;lZc)J-*xY5& zVaJzUeS3mdlvU$p%`)h;ru=L7^V$8+L+8Tuo>v6yUK215KDE;%YQek*%Rp36#A=V7 z!br|VRc_X~I~SHWGZSw=L57))z(6&Pj592-Fi|+9Swvh5zmS65$*0bK<(1*OnSs1n zm%J+?@*}mvL}Yes5eDQT&ciTTDjA}ZI3y8Q6p;YZUlEZtBO-!oEwaKnXq;(G zV|S`sq{QmCPJw-s18-L%%T*bNrIwyM)I)L1aB zs$lNA0Rh95^P7NRk^$_EPwSsLMf=-7ILn<$M5~onT^42;CfvUIJUnc#k=@__`OFya zhp%&2R0e;Q4gQb*nR{dKDT+ZvDZN9SBg_?ME;5R^AwC9UDucgf2450I^i2l;33OI_ zP-LHsPfA=$`EM$`jO(9`>Z~)*Uy(B@Umq&F|Mvd&p)z8lqsnt0oiL!FnCgg?;9T;k zDRS3CW$#c`?p#FfC;;|@e{^qP5X>G@+@({fDG7vP<23b(lfZaT8dWg3W-v&&*6OC! zRILHXb3dK1mfoP%T7=Hc+P1rae(f!f@n3iHSpEcG-5V-!EKV9@2DJ%67Il67J%2lJDk zweuo7FyE9Q5whI?ot7QvE55=#)3nI~Bba$Qgh^P*`h~wjxGB7X|^}=`g;TS{{t$^2$8bp)r@Y-$%&r9wDK^ z-ZCi(304TCtd(GxF}FBK!iB3=(5@L0GOan*Tl$79h~0yu+R}uFsR9cDZ!!q|VmLVW z#mi2=+%0YRd|kc3Cyy4n0iWlcGhbX(p!Y#R&$x)d1`>pYrHDwXgA^3}2Fqq zmLxjcO(LCLqR)}(Jc+b#IVRBNif+#yD%4!&Xs=$|wM5 zTDef|uD)hS$kQoVVhi7ZgkblchmH-sv&>v%`yup};^I_sFb>0Bxay-;;qm}uznR_K z=rZTAe^qM>Fs4@&gVDaCTix^SUr!Tgr_dvm68=}sMfa~AJw0kQTCL{pXJ_Zn#aHgR z=Fhw5v9EH=bcgZ6zK~_Xq(L6O1xm8=LQ<-HFiaQdnxgfJWa?Mbac|;{eR6*=NE>4# z4^C1QFlLG{Eww|6lNhC`jw)L-3}Or+O>W9buh))V6PY|q>E~GyvzncpikcmTqT3Gr z<*ABg)3@1C(b!_MJ8E&A=kit~OQXtLoLRsnITt7f&3VAqdyA0;vq~ioC^)Y--cnia zdhlA%B^J;ZgR#@zNp}`n49r0x7;^tYT@g@ zIm>rbw}CKqhqj%&%F?g2rN2M>(wTIK5cL{Nj!;H1s}wO-M@BGsa;RFryLOhIP%O60 z4Y9D$9`wxf?2{&_&g;niO@)`H=#A>E^EO4z*~yP_=T!!Ol@0!n{^k2)@MSPcNgS~W zo)IK;BwWUzb=1PpYVu><3_imOshcL?r*{&qbp}NzFS6rd{!Q9RbiaTLuWr2&>GJCH zps>A07XN70;va?Hu$t8PppzQfE5tqVSYjl&3{ga(G!fQwV9LfW%ENxAqxkkJ^ez@0${D8^D6tKex7%h$G=A9 zerCF+^V5`wcD>pSi2{HAU;q8@e*ceefBGT-5C6xG8%%`(!lJ{FDA= zAT2B6Pb;wfuwW~hvzB{~BI1Mufr3G4R~!V|uaMq&8x?vZ4gD~}b5|&PaBoo7d54L$ z3?pS}pg}|@2~aPr7#Mw2`J(HFvIJ4C(lNA)P`24>)t8}bGoeK~dpu;V^U!X`ynmjx zpc4lpBUCRYmUKDTj-GQ{sLlI*x6V0v_iTTSbplqzT@XQNBdA5#A?mb}(ktf?k<9Q# zUhEz2m+^g+^j4(7?q>36^T5C8Iae)qfo^pF1hKl#u8?C<{ecmMf+`Q5Mn!7b+SayQ&EZtJV=x6}`Z-9!AisG>+dCfr z+bHc_xstzke~=G&j>HjhZYYI8#z=ecBBL-w35#Wgd~1e$8gWE!%40b(`8VgqFnbJu zG&s*L13OQPeixW%dl@X=vhEGe<)8iGFTeY*e)ZiS{_B7Kd%ySH@BZ$e{?Q-(+3)|I z@BW?t_Ah_?@890%9DL*Zuc`oV72v%e;46fsQaVhibPQ|fqQk*(VYLigBXs?YulJ^( zA64Y{$Nyx7;kuKbpI*VWL6I@1BND`O$I`y{q}(bJ6N?eP{nn5V)3!02NN!Fb{#t<> z;XGAUn@Dd?Heg;@=wpTagXU8}{L3wLn&Vw3Lb*2cX#glXUxf8K=%AbwUQ$gkaRSIz zq=E!Wum$Rs#Cx)?v+3tX{a<}nJO2FiQSrseh&p7a&ixzm&~J^uLQBz(3pzOgZ9k2JU^3>j@W z0ngD&&A_Zh%cU?{2oA6?fbNLHj?X)1qaVN(N_{=s4%kw7tqB<^ZR^Iw%q};uUxC{8 zeLn7&XRS069MU#eVC(Xly+Fn+#9n>4gU=dp<&68&*jros)hr|EIrB6qt zPcKV9*q&?t;pG+R@_f(^4_gA7 z#zIQ!ERCvM{F4aJC5G?T09_E(fZ?@E6kjnqbjfV8!-H)1_}P=J_UKvbHLU2e(&^#B zX{vNuR=Nc_+6P{dZ(anSn+%{b@4&t6Xw=&oz-G4F8=h@8J1>g%i*!^;j3M<>|B@h$ zNYEO{nh@S`q67Dy0Mn5sI_|KS#`@@tjZ?D5j~Tm?HCjp9m89*Ll2$LyI(eEF$R34r z^CB;L@L{dzdAr@elEO;*rbdBN=RHzshhb@gjmSs?HV-Qim}7}yC+QpY3eFTlS*_K~ zo;LQ5vf4p8)W^^E8wV%Z)5DX!=0RiD!5IrI(pb|nfCMBUM~z&k@0#P(@J?-Vn~2vw<_NnKRdUKhj$A zso34Ripbb*9qu1Nz2oL@Hg>bx?ryW5n#@{_FW}nAFW_}{8$Zt;A0ETa!@WkU4qDb) zKjQ`Rgry2n5~HyR!b&d{77Qt=xhnGwS1+D^Um$R-oztvh$}3+R8Do|z7dRD;a$hcI z&_QtkO$UPJDVjB9WoHqjRAtJ>@^{qwMg8ev>#*L0XFqMWP7aTMQChCnvq!CyG+R_Y zzj^Q^`|=Rj!unY;EI1c9dh59ILNVjLMiv{d3^$IO%8GqoD>myJv9+^dHu%5{krHbZ zxCXi}6Gkc-D92VWpktUZj;3tbc&2t}M^lgE?mn4J$7V-u(mq7gMFnqef=5X47*#Yz0EAj8IR-!A#waYS;IfLseqZTR%qbz2!O=Qpxw6V4 z9(d$TQXZVX9?cj_AF1Y>D*1Z{R1PzR5T{5O?ShvPS>Z82t&8wMlvh;l-BLNSc2rJc zrK}S`+8D(cac((5B518pkVwZxk+m{jTiLf!oO%-!bhFlKZr&nJea8uezxGe9Z~|e^ z4WCZ|s}m-j4X->7I0%V3;?A1D7;`R&+aJ*IkRXD}1Va55351KPu1Nyn{E7Gd?Ahmw zG6sz$o>Gh?!@(%zsa2AQC^!rmQC!Vs49*U-t`Vh`s%<_N^wB0GxVEV@Q=4^B!>rNR z#i)*M$|MBN@bXowk?jq9l}K165>|g4B3Q z*|UD4$F*h#{XBy1LHkwK3rTOlH>)3h(cA@0%$|3Om+j!sLRP{?J8hvf$R?&Q)i$|L z_n>~>2{2|ryj>3HIY+S>A@6Gq#gG5w-cTUT19eDXX$1k93o?4gY&2>0j2ie(?KeND9pHvl1U;XWvjr24jRYx#Uv=*xdr<<&f_3^ zQ5w>`f3cHwO@Hty3<|tfXONi=5Sig%*bB4N<)E>>hcMNYY`-@K^S|C32IJCn2;-DW zWDJSXTOkmYo(b%Q)T#>Nd=w1kQ4JGLb{}n`+AiK?8r3#y^ige-K#P=!M|CCCO$_F# z>6^~bgC^dz`&>m~Dhg9kn2N%DFAC$Gjb3|)y&;BBCum9l7Y0#{0`uXcpfFE*#^=zx z7|&9%?m#mYPLJuz6FmgEt9&OR}Rj zv06j2^X&8NXlO5j&+70gDR*Qu`!clKuDD34gJ91VQ6HvcG)ja>XjCF?dqEjCA!YMK zCN!I)KC^><#aT{^czOcHYj_jWxhk5}b6m9IITg=YA)cc~5Rb7YNE4+wuXxUi^PE|G zBxDf8S;B>ufkmQ(!Pp5#xkFm=%f%zfJi0+@>WyXfWs=5G{gdmP7hk)(Jz*!cth|xi zVJRqs;-%^N5$kvofT^5-HR%-X;_OxSxabWpGJs@~CXsB&&O_U$UAaoD`DxbZr*j_7 zr&%j>2jRj3Rl~GoH<*1|*4tW|06yDiU!Ke`y7cS#r#bAHrE;Z+UAA88KX43N!FdjN+z(klKLcb)vzzeIFN@yu zev+y%d~SNL3h0{5!H{R}6`<;SlAy(|Ks~)ilIPuYx#*^)4M1le<)wbi_y3nCJ3Gs3 zEOj16qANAR>#$H|j+#68Eu7W2En7-J&}jeQMS>@IZKc zKQq}yn(>|<;`gek6N$olX|nSj>uzFCNq0U?JgT@zT9kVJ=&HvifvH6*eEZt#y54NI z&w|y81HI-L`51!+x+APd22&HQRqTTx#+ZEq!C$%$&m9Zm{%A*CQ?9hgOY2Cmut(A>{sDzn5}YQ2KeW(>kpT=N>z72ZzeHRYl)lZr)5C6(g%TtCuP#!k z8r9lif2G^Wp&<0F4 z!7;w_l2fy5DE=HvMqNOZQws90wPu{eNU-oedV@cp_$w^Am|gUKJTg}khIHO5Qrx~X z#m4Nb>=?wMTeM$YgkExNo6XFJZd$+A8NlF~PT%$NZffI$`mq%?d7omAs5d|Yg7JuH z9)d6m3xz^t!~|r_G|9g)KnSQ^4I>EVGJ1-CiVl6gY0dG}W2O|LcjpWt`uFw^C z9g|6U8Or=H0poTzEdqxT7<-)kTu@A#nu0PdQ>d65|6n245h$;k`tCyVOKrpp?k|3R(l2MX4#kD55= z;Xg_|<-#M5H4)KEY6)gsATq5cnj;luxeHa;qQ794g+NVYSU^UYG`>T2SduORD|NP%r z;nbDc^9v~=j#7t=)l3QoLM}*<7D$9K-uvoQ^$&cu?4qY0LMyw6wc~{;Ez$)YbY#(Z zCW55I#fSvMIyhsjol9v+m3?7)qsmWS>E?Cw}eZK*%n)T%x(Fu*As^q z9-DbX*-^3U$JqYC-~F?H|4$}I!r%7X+Vk{`@!9a9bJouL=i9(8!q;2pgNyc>o@0CG zr^SyBqy65wFUwM0z+k$(pC<$kVY9TJn{d~UA3In0R%tP1BQrhI9DhOb?~{6`K<0-_ zhq*iAmKsPXy^OP^m+gaoxNx1eUESN5vt7Yi9RrEhYV9bF9K2zz2n|XxZ-W~#w~4U? z0tA#lw|P6^&r-hDDF&H&Ve+=I?Qm^Ou3o4<-Q-^4D+`8aY4Nd$kM7SB$?nkhuV})~ zPCnier&QTFNt(Ko&h#DES@Pz|45v`QVijCmF2P8QX-W6UjJ6uhR&C0}PCXe=WV+odqKKD^!(ow`tA&rHmA#%qf2hxEk6N1vH$F9!I&^nxq=q`T)N=SA8B zb2EDi&i*%0BK6k7g~FT%t1)FtNahu%SmVgxA1|p#Qr#4;xZMjZdZMMs8waM(I02NN zdLvz$#!%jC1rMJKW+aU;r>E!X19o;a{Gphtx%J1_%a5(l4dv%lx>bMLJbHS#w=CQ+ zDU%&Eb{ofgwS(R4(bgAR-($(o$jz-*{H*qhpM$*_usH|==&rWu_C&3t&Z~=uM?XVk^GlM|YR4xJwkKCdlUqsx z3zM_SDYd*;<}iVMhOr$b0r!TTm*!PAIPVq1v-9q7@R}5YR-;ur-aKyBW+b7!x^smL zspatoc4dP1D1~rJG=keHKY37?If0l4F~FQOVOAyvUJ1scsk7jwr>z?GnW?k%>-eW( z4*<$^GVm!c@_xU3tJ(Rp#`jU#Ui=8mp%oN*H1TWil{Kjq`>XVWbWoxrn@)J~mxRg4CSYgRWp8 z@h?I~vPS1TeWA~4J#akDI8|pibW?UJP`gS2?vVma8AF^{LZh}jWd_$qJq&VOI_{X0 zOi7G^QyEF40nM;pkU2{A#ojJWoz*&=p;RA8GPvCdawWF4im^kk=%kj>f#+S~%$S0=^*cjE5aSW3mLJRw2f9)lQxG zI^Bjc6=f>D2^^#LP8e*ol2&pqtRgJJ_e9SfzvfL)leM1hA6|DO80PdgGG39Q)gVP9 z3)Sol!dWkc2*IfIqHzIiS;w4}$55`r606z3d5n~6qNtZrrP!I|FdO(!M9zL}HV1I7ufpB!kfa7j0NxyOi09efs&)=5F((F=Mb6S*QB! z^lF-nGq&iJ*^=2rTxQJ>eAtp)_eBNPf@qD0Uiyf^A$LwltDVH@ux3mNLqcmAvAcP* z%C%FRlcSU6iUS3fD$d9vQ8u;t%|zU5Cx`pji0dT&?ZY5k?L2YQ>tr2+VwyO{g_6jC6BKbo)?tc+rqpt3 zxVYv3$rKJatUWutW>ibwUHTr=#m0f4bY?49-7;M!d)5zNFb}(7#AB*x@_llgE@L`k z9rj3^)t0pMI_f~Y_bFI_k+hBqqlDE=C@QD?BS8g4YI#IpUZmfTEMF>ft<~CZd`z+J z<>Gz2h`>>ql4aTxi&gT((Q50_g49+p7wymoVpxn*;Y$zfYp`bHC9rD~HJE6H;{x!* zAOijk3DL=DoW~xngn$H_=3u?T4*MtBao&HPS<`R$tmS$kbS68^8Ss23{ato{#^r`F3O9UejR$v;W(3{Gn4izd~WpQK+Dy1e&N z_)h05Q<$FJYAULle!LsyU@B^6kVn=_MGzPW5-0_I@hGMfU8b=DRD)$-?CoX;qivqE zSX0$DUlE9)kt!*e_DUcxoQvQxh^UdI0b@C>2vgJR zAoVF*zWk)wY4$Xv_%#kkHO; z4&G+1+T-i#D3{)vi2>X)K#l&qiZD!dHA{bgf=z3q1ega3KT$*(gD*fn62mc74hcoL zi`SGuXS?-B*I^w?I+u@E^DjnTLRr2Fv{tgeYOZu8hsjV;EGIxV!)f-38EL^00h ztut_`=Vx!yDvvbZuzPZ{AV+b0FF(uESt^&irRL)e=EloHD#fT2W7QM`L|tpdj3f># za1XH1kq66d;5gVgGr3)Rk&ndgpvco!(idI$nkgT7vak>CLx*OyEQJ06ND+M5cL2Xk;!0PG*Y>FlpxnuH?fqe zeo`b9n79fHVn`JNtUdxv0Y6LNelim~UmKNhAoqb=F9IUiI4Yc1K}r^x;atS&>1atQ zz6$t_^Pyg+3e(*@*TMk_8t5GSEycwb^mKv`PBq zy0j#X6CGH%Ms4g@E4;w%NQ)_tPo7qaaSs*ajrO&h3t3`}kPZZHSv{m(sdQb~yX+JDh!wJ$I?q-Z&R9 ziC8e^o#2L==(*Jr5$$HSV4c#?Ddl{f2EPYUdg~o%nFv~Y?yZgB1)xBjB~mKo)A4CW zhmE&3Kr7lc?}~-|#&6sk79xYO8heDGI5wCCFoZNn!yGdfOHr|qHDe*1Xic{84J@Q~ za=4U*z_s(NHfX1l=UsNv3kHVwaH=1d^N_=n+QA|oa-Fc0FLH~5qi6R=*3J*pQK0$Y z+h1lrWbL1fU-Vxah78`^zX1a>gJKKl#P*ukbWQtW3N}XYmS$F|2v}|f9L*C4+#zhARXa8f@}*%Ed%z< z(*^)I+S?xqRZ)+Rf_m_jL4>yCV(L-feR{A=y;63`u#<*#`i%IL6!SCyvpAou176NU zMo)Py6Pb*s^XHvX8!8G?QIL;}f@l>O^TtFIqA~(ZGBw;9q6OG%7U_q>**h@>ZyyIC zNFa*573oX>r-c&MQ^b^HS|hSB4zeQsbanquImxf{Rpumx`KnATZHNBO4h)`9QgY(4 zr(UOx4uo?=P=zI-n!U*}l>}`fzDfAo9aDL&>Y5x=xqDdq*=B7#AS3EBl8cGH*$_B2 zhGOrCvzAlkFml8S9t~H7%^e0gJHC_SkBd_uPWSSQaxvexzcQyA$L8BVYM<7&PLDwg zhY3TrPCuz19yIHXlg(!bdq+QAdLHCu!zo-p)o?ayIIC@CR}E+L4d1Mz@1WgLlW%s= zP{rp{=;wkqQ4-o~7*bXGe<2P2ZvuC%#25;052lliueBmCb;DAKcf}ij@Q+rQH_kc%C`QI5(P>LE6HKr^#cye( z$Qh$atYTT~70Y5oDb8++Wi>iJm={GatDl3pO}jG!Co0;@c;NCXqtaI)sO>e1K|O0N z@}*k?sQhlv+kRI(2){M&Sp=q+*WO0R0PAN}m!*mq1~MA#T?kc*6Pg``)4fO*%3 z5mwpvHM8$TGa<;9Uu@rNwRGgn&BnZT5qdy9J6WyYFWh+Rl_F+G=fM44KRXF&bCq6y z`CP^5DYs4FHKsdQ=c$U7f{D>=#>b5k%OdD=>p~5&B3gu*(nKPMz{X-LiBOgzCG5uc z)}8kx4Yx7_cNAp*(NFFTm=fuQqL^~Y;75;SkU|Mh2%?@a5-KoVFE9nQr&8XOb6Bq( z)s}(jpZ?*mzWd#O_-Ft2fA|-F@Av=WZ~m=6{gc1_7k~1*fBMJ2bAxL%jfvl!J@2=Z zP;a@;y5eGe7AWfHdBSQ2PlNp#Cjbja(+N_Sl zkO|KWG{#?({BBT#zB6+)il=!CTzeh|T7s}p)xrhctVy`~!7xbXJT{?C?K^{d+p z>HA~=z5*MOf3tP=V#^HHl)u+bW-}(CM|%1D&zGzsTho!Ph!KrSArl0{GNOnH*8)); ziBs6lMz$V<$JI;cmFAr?8!}D){45E!Te{=gLJhie@wlrH*8h8da84j%qgNCeWqm-@ zQX(V4f<@#R;uX%V8P25@Hh7CK#<`P|tQC4M@_zP7{hNd$W@!-X=Hko3Sc5^othD96 zS=TUD{WoVlp454le$FcTI8`|7()Ry<_r~^fqPX%{%Bairknl%x%O#-%Ii{TfK>I^{ab>BT88ky)YJQETq@or2~r`H40E9a$DiZ zdf^C1Tp)c@Y^`oO#^RJ=RG&NI=dm>;?3gTq=ixC>$_`?PRQ~< z`S#x$41MTlwHF}u-~JMQ3Y~2K+h3*~7&{>ye$gr}pl8}|vKMFHb>P;PGwbT_)n^X~ zE=Oz?oxS^yH@A287&j3G&4cAQFll7)(kbLULs&^Nw`k|hb?mN%;2qhKyIS;maBuM1 zfVamew^6$gJf_%7CAnl+c*m`-j-6XSyp~AZ6bt?Gq`7o2`Lvx~ualL-pZ1CyS)$9> z&}$CcNR8hPS4Yno%seKaJf+%BVnuws3UX)St5I2R4Dy1($0)^!ckssui@lb9_7K-M z(xeZwjl@D*a94?i|M=bjsttr;f(VuvA;ugH&Po_{iG8GC-77#{FF<8X2t~K-VnE#u zofm1>yl|0sOmFEDsl`Q?1wwsUqd%^&1=gs7#T9_XD)jj#uGGJ9Z!A9myWq@Vk+$Z? zf)L?2Kz=%>R2b)~T@lvK@+&HCOe_5MclIAGJ(#Q3svkp#G>`Tl-NM!nFKlninKF6& zueUp&h0dCq`qfGyuTo5=T_9~F4vI#tu(Mz#16&X~punhz2GNa0@_(6Fl6KQe=PPIX z1z3+^+w`*0#_6w?EwH*l&)%2Z+?7N0KiwNxj8bA8i367xdxuoO(kO0eI*OW8Q^Dfe z!J<$YZ-vFM__!BBig#o+_-}vM55tRPAbE4~bxxzN+@1UC?)>n7zCU(dBceD(01>IUgVxd&vzND*IXQ!Kc%#9v2aOCux0K^`jcBdL zhHsU7Gn+v#F`~+8Hn-mp{2@VDY$Cde(OaCliPa|3o0zWQ zshbC_#{iNCV*{GCT%PPl_88>Umlqd-qxV8vW-!OpX&-cCBAQ4TV#*sF)Z9s&vtvG< zcs>0x2h-c>=bh7X{YuJ6KP|`WEG#&1b7s!=vTAl&HM^`jrNGtEmmlHLm-o)~TIb_0 zuYLR7orjtCkIEw~^RDR(mK}--Px=bX;Pn$R$2T_S43=j+5EL+#VB9ou5txUwNOD6Z zHk6Hy!;D}s^Um4m2XHP@U(dD!rWRgn!a_>ZyD_oC%k1x0ptXIUk9!5gfBW)jr|opw z|Em6<%33d8Xd5eJ3IAetFe7p z+kLP-_uz+@S70deLAyMIz1s`mM)cFt#2N_hh!tcoQqNM)ob`+!rZ=3tLStg;pd-sB z9+a9dCE`+pvP|qi%0_d8*;6nEkqhn3`3#GmB^!Ns0pS^%DpZOy1=cChzW<~t+>C2uo`eFB3WB!5ox^_)g1s`?? z>C7XL@N5tG!l0bQ=?y`I$9Zh&+d=TV=ebLf+bPwm)abpakz$l^t_(FQN^q2rkV;3v zJn>XhB|ije%uCZrqyF@uS#Q=3vc~SSdhMinc#!QjzG&{PO_up!zahJ{j7Pg z+x()r`>eJHKekTh3^n1HU0H#(8DT1wV^Mn|c;MbT>_sZ-j5qz7JM(hYcUD}eZdY`^+6 zJ1Y8vtKUnFIu3(juPpjy(R&_x{j3b*v_U?68OWL4&19*5B|XSH!_?T>H4VFd^Ly&p zi1I3qNJ8&513N?s##$gPgfvb|qCF0p8BHw_!i=5ZvF*Jmzax>+BoF&Apk@@L+YSBv ztTSamvy<~)F+4lJG_;$w+ylQI6}%k&Rn+JA>s)_mfGNdYVL>n@YbX4~3W+5PDx`3C z^g0?GS+K%sLJeEt2+&6cI@2s{hMrAXl*4Y4m|-VP%N+Fzc$te?e+6Me^r{7x?kwNs z*Z#MAGaDEsmC_ zS#t;6n9#c@y6459cu};W;~cm!FLIz**&`_8v$V9lNxvW^Wl83=ztYal>wK2R!IQV< zh|P{4ovzb{A3Md1X?~gpwgdL~Jn!B>PDc+O{m^V4y*@k$9xIYUt_$7!n=4HBW_d#h zSTP(WW+Cl{OR2HiFyy32Ar@oai0%Pr6Ps97bnhm*H^r)EhoRL?S{{0bwX2_RB4Jne zEAI7ibFbamRM#f}Z>ICAVqGi7y6%o-r3P|;HL#2LReIS`B={S4f zS;8tWti>)`uZZJ8P{YEAWfd_3!<(}^huyU5dgj)Hs|TeA5A&~%#$3i6vNGskvPtE3$joitwLbl@y~OyIzVd?NcTd57{Lig8 z1@ndJjZ~3GMQi|tjEE}GLGC=Gp8Du?5X9d8oUX*9fJEUh)oSwOQmffztFJ$X_!~D&yJxsQfW8l3Z=DY=+W$X$?;0Cfww;INk92iq z2XT-fKN7$=m;lzjz%6pWAJo+t#bU9W(@i$RV&C!AA7($vnl4sR_2`}+Ai$Lz8%X5D zFbvyKEI4rN#1I_IvLeejenbey{*xcZTq7|Q7%*VN_e%a57;&C}v-YVfvQDw8y4X#2 z7g=Yfr-wXepMB2Wd+oKpwf1@xqsvMx`2exxeM=bfuo2}ugx~S#q#;p(w2<7eh%DE_ z`anqJ97q1qTd;~LUh}hm_m4e)aJfW&;{RP?M9_7E7gt6$W=InJ(jy-LmPgAuvVu~< zsd2E#H$emhRgkREw>g7LkE#mRYlsLgBh_m_nXcLDWzV0?LI=hYPbo%{;b0W<)GA3* zEh(JLXMFnDt+>o&hmo41+ZCd#s>0x*iqg9~6oDJin5G6}4p2nI ziNK`#;pPzxl1RRZi+HRqk~#o5rQXwb`D zjz-)r%de*Bn%4_Y@rvJnR7;F};uvpuVK&##nSSy7?$P%A^SknnKouG_HYqUf`IE1{7?Qh{s@Tz$Z9uuZqDposNAr)sI-M7>**lv!yzXUB`=vip33y7tQv#k_1Uys) zE19E!b&xS$Anm+i0mKr5AGMqSJb4A-MRC~g4~mS~Vn~n81SAs;mdGb?5I*l`k3u_) z0{3!HE7Qt$L!PT2xLiolM3*@1uEESdx;J1(D`PkzJo)AVmPvAwBOjs`geHQzIhY}D zlU!-mqa~QRMN^K_td@?@cB_PO1N-SId}$t* zH!9_pJ#C&hOE>Eh)|9ZOgf+Ko#{pSnFjtCs6e5j+BF8O8)_Wc>@$;kU?jeX7WynCB z@S-8AanVdkCo2;nddZ;P2afE4RrlfE=_TrUU+Cs1|HBnVH@yjW@U1N;4K_hV76B0( zNj%dSVIr7}UeFZYcLUcInOuMgDZPhpf^HhaXtBntX0LbSm@yTpBe2~SMNA;&f(iS-srgd=!&pkhBROcb3^vgW^ol4H;cshPq*7WfT+l*ufjw0drXx@fs}&?L zmSm9usn~yGIwY+z5tFurL?|M$+T;01tY*3a*xFC;hE}WdY7`iD{bRPaW;9$nJZ<8c z9EBPGGOeo5#+(p3Uiz(DTg!B}M7D!Ght+65`9b!w2_%~NkhOlQd44`wftwK()!cvX_~`=UJk#&I=Gjy{uL{;;C8f57my? z#`}VpU;mdY3^CJpnUj;VWVK4!=B;&1aib$*SVw7;B8D3qDC~H&d|jnW7iau75R;$^ zhCgx*A!hB_(M}aGX6@Pec^=s?_A#pVP4+2ly|c~$h`y3N2GsTiv`Dix)54b0nQBa# z5|VkvDb_ft4$({Mk({=$73n}}4Ua0!=jJAOx?MjyZajT{u#-J`w!i=UpuR+{4M23E z+wZkt({K0}^ZlTQ4yy}5V4=Y*3^;C3Lck9gQ1_&Ob9O@e+;m^8BKT8y1bnDsSaJCd zwWCV#_kO@%kzY9*xQvo%ZHRVAFeH2oRC2+!LBdUfKQ0xXc99D0@XF*NS)jpwYG6UK z$HDZ0{W=(O_w{A^vj7jI?0-9HZ~*4=W>>kHI<1NGgg52#+p88xVIniYaC#?6BDk%5 zsQr$aB7{jf0Ae9U-6ySlf*@vL+u%-4u7F*=RzSAt*U?XdE=U#APGdg@h&uzx)}PNu zvX67&^zrn|wzl#cOJh}-sCj*CZS7ST;z|RA*?xWg@lpNL>d{VGt#5CRuiZ89``Z6; zZ-Ae3h%%`aAcbH8lUyMrt;Hk;6rEna@Y={gNK4>%FM*#{f-r^EEN8H*=#=`?y;?PE z9991XfA;;q^26Wy!+_YQ+s(ldpEph0x&$QFwT5f0 z=+#s^0|=LW<1lnCTH&X9mjT0|B7XB$rS4FozOx}_k&p$}Z>A%i?yLG7hMB4LP=*Nf?{@-*Cl&)yNx`8}%~ zKky+Ror6uLonV15Diju+10xTFqteW|cIclg zCN}(R^j~eg?hkr-`P6V47AXQVTh0OTsjY#=Pdd=5`I%V`W}D$tFGde-wECN&y{>5c zY4IHCX|sPeNUu3(@}(Ca4I-~qrWyObNJB8Psy#pkLZg50UF6S8|w;P9xFbLevwo|sg(CcMDlbud0+Ya4U^9@GDyxV0heRlMM zUfzGj=KXJglwMOL@*axClsM$Q;}9;Qi<+fmK~@P6wjvTlQZ56e4Amb^ZM(&C_O?l6 z8LsfwXv0TYifAI4^_=WUH_SN71>aW9pe+&Npn_vBPX!i?0_|sqg&Ee(W`0D#V_@iHa zANu;W><51s{`dW_ejVC;58n5Ecs#ZK(@Q|Tw0pjIae6-3c=5$%N@u^8$nHt8&c+oT zl;G~egS!V)8}N!F3l|l^)@hYeA~K34!irlv=KJ2NQc4jApN%J8@MGIcgOq&)RH5J8!6 zOc9E$2q>z6#Pwt7+rlvGGsjW@Z;{V%<&4~#=CbU`0;UNg%*rc$X5JX<$?ykA?SXkOhO-nnji zKRb6XE;dd(FE=jM*2VU)m`3K%ylCFKI(ADj!}_gbgm03OdL_buxr-67p2Zq-O0+S^ z2FVayC4>n*1LVAEGnm);-uIVMIB6QK@cCk!@~u zBH`3x=>;ZQ)8$KKmon~Q$T*D|A<5V@OU50AW;>1QC1C1m_eE$e+T`;Z&y;`T#pw z5Fi<>QPOIKm@k?CnlXPOF<~2GHuJBaU%=OotS66w7rxF8yB*-0z;d%{ua^q#q}f`S zn&oDFOpA)mHRAvGE~$Dc0mi8SSJ^qWC;>R4u;+2`L1Skl(^7a42P|3|R8(c8{JKd1 zr5G0*bdHJZ`SacVg{ik5cX}6jai2@8`j>yc+w5fCTwd`&3E3`CT&fS`JGpJXefH&F z=qz@s7{7a2C)TsUAfB5I+g(%jVf&~+D%)N2MYFYncC`C1HkP-ec}=*agu4W{h2utg zp@h*k28@xEAKl4TT5=QLH3i*~t?g^S@7@Sop`4NwIK3iTP{)-c+NNk_N=={vm%?_< zge}IJ^Lc@(kIlI^UB9Fs<8S|Wzx|i~w?FdR|HD7}h3p^wJpAxifBUcf_Fr8h8SmNf zEgQh6%44VU*lDH2rHQbe6$h=vdm?m-)iA&+oeoY~MOaZ>&f6}th2RpK>)sweeeI|2 zjYyP)aiX=5ig`?t2{t&R6m~K=1xsFv#5EI%f)Rq|Ss-f%^@ZB!#QjAw&!r5Fm3A;2 zuDyBIKW}YTZD-IwNsq6q1pH8`WJ{@dW2va9)hZ&&JqLvnIc*|xLIr}Y4Ja8M{pA)+OOGD{;3rKDUl zNr@HWVk69vl#llg8w*8cNTEX6*vOP-AkRVOI;r+%GAD)Xu+!}I-Vp0HdeO30S=hIg zi@e)PuU|P$LBY-TM(l3FpF?vRD!yWz8-!-7f`!~j!g);v@@~=kw%g75#p;RPb+X?^ z&O!`=C;J`8Mtd0%)--C2EwP+@bPGG|t_fi|MsZip|EpXbcPc-Gl*(8kQqh}egBO}( z5>j{%7QppO$H;Y)w+d^f<~c@g*Y+2t?YX?YNH0y3V_KEiv_ShnB(PkmxCw~HQUITKMOL6%y#HG?0sSP*BE<4&EumNjn;cBgBJCA?8-0J`IKmOAgFSOj= zsEc_b*PmL9H@bs$m9$6C3v_TafXk*ma;8jgC_^k(ImF`Qzr4Z%qTM_@xe^dT5E2O1 zR7w&Ns8A9`90OyNE9sS8T0neE5Ed0AD|qB7dac1+0g@h76{IWU+J`e6Jyaocu=f~b z%)y9_T$Ru1C0zA5m{$L6mUPiUgCZ=2msAr>oS-2_DhR+lYz?JTxi^ceUVFS(J$Q7o zU)?)-ez5nQ`cY%=_`Ai_niDKNZ=6BnY_jnL1E1i=V@5G~smPzFT8u7E^6aY?SC{5+ z@vEjY?_Ou|R}W0zSeEr)^{`y?Mg1<(S5cH)Juq=?O1fONDO{ZpITI5+zA_`i?*=@1 z1*DHc#eW!kYiYDZLdMBSd2G5bVWorraM>oO#!krHrJro}4o$b;bj=IX?k~zg32*ug zc-{2`l%pFTU6VvXi=Z&q3YM5~$GHnsXc`&z*zjTY$(&gE5yHoxB2aOatRN5?LlTaI zwr{pihd%%~PwP;82k=_>|yb$ZP3{;jRi11E(CPKFPBdvod~A75U9MQQe1 z;p2LYFq`A_mXG(olLf%`;XEnNK-42d1N4v`pQRL>Z4Wb?=ZXeHw7qetJ(ss}r8W4B&|M$a4B&R(NlZPXhxN%N8#FMB$9wtF(_ z=>&Q@x$5a;+|xpu&37t$zK^SW2==zt02#;ocWua#xoEtNEJ}>IcZ6ydt%@$vpi%U6 zlGPQaN{^>%NN?i}eMOz=my`%O4S3MYb^sojUYJR=**A_K1Ei}RKmTS)zf05a+R&)7 z9(xKTN|Q^8=YnFRXfT=>fryDE%Y3gav&aX;`ms!;9E*Yr4m>ii?Chd;!BGuj9HTIg zWnxmY%#vlk9~#9vSRH+25>rnsw-j(DAWbhl35KbXWxi*Yi6&SkT|1U(2#dy9q@uw# zgrK=sBw{Xvagix8Nsc93{4g|13SwQY9gR|I1c?gCWWn|@B#MYdlzPM>R(`%%$E8>= z#rpf9(Uca&5$2dhDX1d3m4+Z4bJ>HC;;-g&VYmSAeAiQ?`)MDp=hZ?1X zk4DLeq7X57raToEjg084K}_$@P<}}oSBC~u@}o4OFF{)lnP{WO5=#!uP+LhH5&;Rt zys%`htfr-`E@k!mp;0b14MI==k4lI@Vg$J~($< z7NMblE7&{mYMqL&GO@1>Im+M><^frd-oPM9K!E{uN=^_%ftLo#4{4xWKkmqBa`cfn zP({2aoOo^(=Nwt0L=fc>>-pA^7B(p}n=XwDYVGtrqM& zYsfl{A<^pK1B%`|%4HN7ML`fjQDZ;XS(2<4EG(TRSC6(NHXa1Ca*+w=2xit8M6^_# zG0dHsYv)0wou|}f-WQEJA9dtG3Lc^m&RD@Mmkx6yDPB`M_dD~r83JSdaG;@*13wcq z5`v_n5^3fl;h>Wcfr%<<>$Yf%uN`fLAiM{DB>=ZM(0xI`8XKvS93utF#wyX)Dhs+> zvQOiJeR}aVb18*hmXxCH?Z*zedsOw2W52X|#G{cQRVN;hMQ=YqtZ$ zI?7COJyzX&p)E6*W9qaI8WhWDB4LOrZ*Wl4vFe32f6{8cgsDBLdUJkqG%rYf)GAA@ zvZFFO{lQ14-?#d+*Wf}Kp1$f(slbLpDm@FV5Fk>JMr)8bgen~{wptibI2}0b^!hs; z2QqRpZPac^#{S+}^J1|@tMFRjw?*ueexJfVvzYMm$Y%%GbpEORkb(RHfY(nFqMw7g zKVZ%;emXlmgGF#xZ|Y4?4t&+t*8X8*^I3Ig29zmYz?Uz6+3byuPYN$x<}Je?cJ{9! zCtN%$fV~ZrlvZ{kDeL7z6qB<~T)x^V@CjSvZjP^~-AeMXHoBb+?{ALqE+UBJVHT50 z#hszJfBoONHz-a-8I)7bDq)zA(M#uJP{fId48b?fIaH#!)kks1mBs~Vh~Xq9TsH03 z^Kjg_U3S^7L~LY*asZ^wtP$ukB%xlkEg{1c$jY*03O@$iSey~8(vvILG; zDiL)V8892D0TXEFg-{=La~hb~3)8pW5wH#Mcw>9-2*7SSliu6P#-gZ~&wXRijUb_i zRdRYmc(E3~0fp6ej2nqOb&+GNsdEx(Y8ArXd5kPB_s-q!o$GXZGeRBiJwXr?cvbe^ zU7NT6$-PmG4EB-um=fV}#1ZT=&9MmyWg{Aqe+$J3m5R}7D@KPP08YC}Gdk?N3f+^Z zPiymZqsyjQ-Zaabmg-Td9+m1*sUF=L#8XIFDzGDpGNnBAPAia0f(jIs!i!u~N{DwW z>d}XVV?&6j8B>}S9eRuE(Z~q|Cggd)*#a`%ticR*&c~HR69}DBknRlQ{ky+>e=wes z92py(<&0=yxMG4C=bbQ;W3Ee#_wX=YEp*L!)1B-#+fCpSuxN=$@N?^1**>sg)1Gkf*f;F~;I)2Ypr;c6_swXw zw!go(5YDcRX=+d!dXEuC)OpRcR>)DSs0?f}!I;9B62(?UjtsZvqZD|OZRgYr zkS^DhdnpQK(RMDkPPuj7ed}n+Ea>WyvQ+EW5U*grILD;ZNH|+aG_~6`r$EmABx#1K zejYZpW6sTK$PPg)^@l|!vz;LxsM@YcvI&+5)VDmeDq)G408c8ckY1d8ssvcK39x4K zzA=v~R$0Ehcq>P?Yp}0C6iF@|NF(GGHdcF2oTM7C9djJ7sjtwQQ28kCFYdgmznI;^)5oY6~42pDokweR5U}VqIYPm&WYqop?P4h@ft|VXHWaS#Ci`N z>m58fc=qW*5%7(#l~AvQdhZPNihL>MOHtTriWDPS8!fm|5m_Pw4Yp833a7k$bP>`k zc70S!d~^cp4KK`Qx;f7+V!TJ&^D*8CY=!jL$JbxGwKdUTiNuA+XCXTXz?y7l&^_yP zK)W(AfKUT`7e3$0s#&eudF6X>H*wwsrLqKR{7L!3fOpVkh9EcmhuuR?VZCTu5=X#6uF; zfxVSA0Ac}8+DeXO<}}4GxMsikMQHc3SIz!emNsC5#wG(i)~~=c!o?oYROr865d>V4 z%u>c+hYX8WXcCx5E;(QsY(R0+QfU?O9kG>#Atfb^tQL)UikToOvKM0)81@1w#}$@N zX~Ke;q>9@A{9B$<0eGFA%fNQ_2APLwx{YwZJ)93+wtgcl{zQ-lS^@@k1kgyjm|mPjTr(=H3QlM&sTEFGL2YEp zBad%xdLeHU5jN}5()4nBrWdM^*xjk`R(K7jnh`=OYG)T!YCF}P-8z-KlFf|{tNP^a zpYlnZhSG0l9c(b=$x>;7d7qfZIUZs*{Q(+GMejc^X_x+h123!vV!e&vbjwtAJzD)wLg#s1uq8^x}&QCHc*u1fIpu))tx zy&&Qr1=z{$*Cp;LanCK_o+2ybPJkQ}CRooIjX}f+!i=OpL3_j|Y&nP9+jU&2V5GQM z7$0AJLt{EXzA+IYzXb0tf}Gmp`5>oex&c_)PhZtp?oAK3k;kdeXt;E+{KPZ4*$U>h zcah}u%aDy3A@sfUi?_Cx>~V=;`p2OQ$h4mwnn5dj)J*~MS^e{VX!r8zZT8OJmuvIy zJy>BJ_o{z#aJdxN)<4}kKevHX3jx-B5!g0EScm>I~!EpfM@OpawJb#iM z4(xfJtUBdYXaT7E6gGwHoQLcW~Rxaeb! zbFv2n)9erW;bgbdJ=tz{TAkCBUhHI?AEI|sZTpi^j=p&)?vjCBc9&<_zUnT!>@I`u zvdivDB=@k9+&wd6sUecVSQDg)(wvuYZpGnTk*^U;l@L@R!wUKn<2=QJv>ICX+nBXuiPd{P}S(t^Oz-6-WsK3o(OG-t^2Hf*9ZHW*nWq zx4(FOKK$Y-QcNSbxEfCy#f9mgjYz&&UE{UQeZ?*+LXM5f({5=$q{R@@?I;AIvhyTc9S4o4k{j@bo(cKL6D8Up7stAC&sREx@iKiz1j=MS|wm8A79>fl#6X z(Ud#Sot-@9ehhmS1Zk^jY+io%TN!YOO8S)CqT!ppG<*<``NF~o`{6vHiP#-9`@I}F zybPxxSZr(BS(v~->M}Ufz?`&SpMP9?TCX1L9zEYX{`Thh+Dr%-+#~|4*9s6Y{W|(- zkn-o7cB*Z9-t6^en3LIeSXuTOVI-V8Fg8;=T`>{3uBGjz)OWkWlFKuD{aOwxc=Tz1;+3@!?3nuAMUvH*w9 zYH;^CQ@{SN?hj;S+M1LRUs0lyVidSBurV!>o@--D$oOy}qmWFdDZd68FL~O>JM|~e zp6(qy8NtA-8xz=a+$Q^U@2LK?-e_b`k9SJkxT?7EcFfCrPYe8euh%u9RRYHnINmyN zjL~sHEfR_bY#3rxMHLzK&LRSTPxuKCEF{N^D`(aYr%EZcTE?af_vz4k{0X-JF@~V? zsNOQKGi!Rm1ABxahvak+`mZ|O7dcMt4NvEGD%nx})4hY8g#jk_2z}xOs1YxXKKE+J zi~8Bxf(8rG=NQb7C-)NE-!TIG+JAL#5FoKmA{)JyUU5Z*!P*56N*Z7ZBx7kbe6R?R zQ>C=#^ONOQ8`-00&#R3Bn0pm0kSbu9*2fd%c-k45UL`>qGZ+>K+;E-qZ*NYtE@9v* z!N6NFAMPF%gz0WK=RNNm1rCR@z98_L6q}@s3^;f5l5<19K+6{=ui^70T*7%`lO z;3$Y~32-=?8-=O9n}o*jN0t(Lj)aB=k3o`t0WH#O&5UD(wX+&iri5g$q7;LaX7I0< z)FU|^$6BNVO$9Vjc$UDvvdny1J=!^Xc6o9)(_}MllQoW>E+O1snXd14tSLqMYI_de zicH@-E?Ra{hU%3x?BJ16gDQpW;2JPjkB8Hc-(Moc;ycZ5e_&b}-N}G2rl8-f+W`rc zPRu&(Rb%iv|{;8e%$q=!&E8=s6tTx(PsTll=M3hKz zi$i3AMe5kn&~I}-wA*~Ju?Yqg^*TuD>`($EzptE7Ur73H*Er-)1y0=j7WiA19? zGsQ^H{KB+2YxXhQW&x6J&I6#EGce}n(pYkF%grM8+nfe^o0Fh! z^MmG*9YW4`#&V0G8?Z!|R|)QSL#X8Zu>yDf=(SUgmx6hDCqGiWqEc(>6PY32SRJQX&!D=_8#D)V8TP*uVtzLh+U2S}GRF|5(DQI?)p)WDv ztB+^Ga>|%>PE&7^_nnUjkOiO#hA0vrEz5D=7q7XgyqGc*E}EICa>7It>wrF$OfK^t zJHfOH+Q(?PA%5j%=8g=azi*WdqD53plO+rR7(*fiC0yXf3+F6AGarQ0r9t#T8AMm% z%yevm)l_SOQq{LfY`wtCZf5%_=CynHhZX_g-RH;8kLuasv&P=>-m`=34`q8hASj+@ zpuX1+_6{B`0g2UbMlpX+;}yuYb_w`P!2cfXxg-d|tgw_2 zr!~Sp0+XddP>Cob)J;Zs9K$Y47R)@MVI_}Z&2v@cp&Y$z2>GAGAiHTA`>(e~x8OtE zx5k-eY%6>#ccQCx+Oc^$=%#p&Y#(+;t1@)COE()ihZ$WMzjr_M&pJNOkue=1A{b}l znz{6OB|Z8^OX<;Gb#`1s`jV?O(%EqBZp&VJ?``C1+U8rx;qF5F_yZ1IpK{gXNOKlE z(L5SV3zbNz7IO>(4IU2YUGm2}fI1!<6jUW%$p5#xDfx~fD;ki5B;(Luo?cs!j-Ht=<<9hY!@#Dolxx+RK-E!Z;oKf5f z+;9~vVJskyRbbXTft1%2Axn(qAKfj+zH8id17k)}2Cvt=+?wg*f4VoO51vkoNT6I& zrJ0YG6BRX27Azqhr)BQn2b=qMKY(67=(fYjK}Z6n_ZrCGz;-*S<$C4GPPhQvkq+cf zI`QQ2>i+RrIJwN@`#Rmc>}#$aW5K&S-KlrO@aDdIsrO#7kjn(07$MV3ObS>Ej5GJ_N;ZNN7?@P8^KhOD;pHCyE0uOBv}g|_2SHg& zoAxx%l;E#Y#O2u%fLDCcxj2LQYnp}8gbzAda%1<=_I@^<;Mn+=iG2K9=1X3_(}nhm zVNUC6WB-tz;FJJG7E_t6!G@ti(;#C~Q3UriaIOhO)&~+XwrD{Tz6VXUtDNF{tWY>J zHuof^)G>eqI>Wp??##4LLl3x;>BEac66HX*pcORpM}V$!Jl9Fd{t~kTf!p$VOIU%N znKj{+FPlDbLs*y>xlw7z-x9kk@U|`JBHKUO%UYfGX)}3Hq($z*4|y&`<2$X;OUPsR zuGg^Yr*IXtyD5Y3;r63?+KE&vN#2lDaFHfHB@&GDUV%#HvC)_?hjd^>+CY^=n#7OZ zFY0{{i0KAKi{exnE=ge039c~@gmWZtRG`~NNu0!XRuJ0lfBu}+m{fMgMI+~~#xg5$ zM>dR~@b|`sVWk0$8mTB@FUTNZV<<&2ah@_HwJ4pMKde*p`}P!OlrteV#B5LDy@Q3J zY~#H59T4v%%k5*!4fhOb^+w3@)kN5+HRA}DgRF6O|J z?|@(%{N4Yo*=qj1KM(5jARG4T2Frt$mxC8(sq3j$3>o8>vo{u63g6gEMu)k##tn^MI?BIGyyrzq``)B6N@I7x7n<>#WL=k z9N!xGB)0+(lListycLESVAe>65Gb-y@xl}?U{w!b(r(Q#^Pk@z#N?>7l!OqYC(?^Z zlDhqZ;SW1vfRFAocbhcSoUPCw-cZ1=O;*&v-g zya5gkU$QLndC^Q=w(X$pH{97~Xs@faruKNs@2=VZB6M4(eLZJQiE-`|#xa0tKp<0- zk{=@)f=~nrVuBPlvM6TRYwm&=Cbsz%8<;8ZXS0d7M<_f{YrWu{avU+hlpwU=f>RW< z(EI~Tz+3RSx0$0`D`@ubuQDL%n9p*TgI4GPqSpvZhonae3jiimagLY`F=%Zyu{RC$ z)l+4TZ|3c~jun!3o>f1oR7VRk#4SU*xU!W7PK}}1JL0V6R5^?sv4Tg#6`3xETwLF3 z4@k@OnkPG*UTB}}96mXDzISla7yt`Bc{FGb+NWHdQ*bEJnuTNAwr$(C?VOk=wr$%v zv2EM7Z9AFVTQv_eFWp_$)oJYmsy3_MK!~518Q=O{zin{~75rb+^NOOcAux z+}38hq@D1bp!3X()!S}vm>+xW<4Tv?yXtBV^?y=p&|CjYU&lHgs*$bQ9<0sVP&~biLe1K;b$V}5 zJ1iV7nEyLXZ%`KUbX?tiRhdZP-XXD<>c}(!T0Axk-y&otC+}|$6J^rZvP`D`%<|Sk z`+0~tb;BpQzap=WK{~9SdTk6KNK(q8Bnn~7qZMuwwN7AOmXyGWXd8f}j0vUL_gS^j zm-kl&ykW!QL+^PgFZ0UhEmIf6KuCPd_(fSEL7>nY(u7b5q_5iWc+vt2N(F!f_(u+ z2eY{6Gt&Fj?R8U%%|&u_Kh?J*(|Yr3+G6E*@*zB~9LEclJ??Wm1;Vey|Eo%MD2Cp4 z{@l|)S9?rY8T3%>9SVmgE*)IZRg$LZa5A{_570(r#Uo*PH}0eXXNOZ zm6TMs5=rCG^AYL$8R~m5^EIvij?Diq-}5ribHDTbp#NTzI_e6(`L6|V)p(%l26I<% zj-RObVXWH$0-yoaryTqdJc8Z8Q6tH&+GvdKYZ>F;iAE51jBE4cGtZ|n!{9eCtfX^xa8Drd9R$jKJf5lx@w5>8X8uK~ z@BudJsJiH($J@84VGpa}AA?zp_>f_8o9Z?R=@_?i`%HDF^Kc$cq&uK^v`@2Ldkvrk z|MeqXhWCONNu~JyqxB+-Y$&{Dq5c@RrV!zEc5YjAt`qijWrMagBe&C3qakor9*Yk7 zkvfHWTuPF|4Q)OR2(B!Ppur5~P^u!gU5C?gb51GR4qfzSvIfhG1kJf$RqCJ^N#`Nd zgUToei8eUVKNYPNSsKR@l=WSw!TsxgXMFz82H%s=p7%`tcPHQDT<@Qr&prK*?bz@B zn*N!d2lMaIo9}u3-^hjUm!Hp`*C+h1_nr5-m+$49&m(=0KpB{;1+@m(W4 zNEvC2Ri3Y8h)1rg8nUV~rMuK~2qXb}p?^}D`DNa-AfW@v>*u2j(Tj%w)T*peX;9g; z%DK;zCQhgyVobWP#VjC}QSP->*YJNzRO1mAia{TJe9Sy9v7~IpnQ&W}Vk4TIa0~0K+)D;lfNBERXQkhc zt$+F1!cHd-6BolAA_Ws9XL(qMwqYsU_Ovmgd{~w_hLi=(J^_8~taGh>u$~j6Y1Ft> z*|7eQE4xe{--a6JC)SA)GpZ3D*NbXXf&j$=-BXj|VrHJ+qB$9y&bVagkim#!<*LSf zuR%XcerUeZ4e#-F^Bv4Z8RrZsl;VV}5{$u`1u(7;Sx772P1(209?T`m7>A`YkL-DW z?kD-H-hvL;IT>wRwIJmbhuCbXS z@mlv`e6CC>9@rwrDI5?P#k5EKhc9fykAqg$`+^LKWJtv(ZH;Kpg5#=$VBJn9MfmfW zh?Ak`jY#(&tC!`#-)Z(qgNI6|?&gR&&oVB(`X6nxAO3I88`zH(98KC*5lTWVQw|FJ zN+3FsLgc~tgs&RR4|5^NHpG+KpXkcwc$<^v<1ayam}zv!ANMMB#-9asb54tvELnJ4 zzN#Z!nA{zPuE?1c6_lj)UT;)z{^y=;e1|-pK`JR>P*^pw>mU{_q}ODQ%JGPh3o^Jc zg`_ED@TTdvx4i5W>z0K(O4+Z-V8mgkOnK;_sf3zTFYlwb_Z7Zwey=U@VC!)t#H3|0 zDRfB^Bqw@eXqn&JQ?DLe%f{G-Z2CL!SM^FZ5TcR1?J9Udr3 zZm$M!tur0n%H|E=g>iNjbQ5ecR2gcs`+c)SPC)R;Jcp{S{Fx~eN2S|pN>8LSZo{8R_Kh6lZq zH(oNnX%j_g#6&|fw^ECe&Ek8K4OwsZKU-^$+xJ- zZ50^fqC<-L#R_c0c`GUbxV~C>tHujnrfP~!oj>zd?o0D)d7#8;Otb;QNfhKHCw)xx zK}BY21aq`C2cc#(uEmNzU*8fw=v~iXhkUG~m}NLjs|u}Dyu$}XzQu?7=wmZ1wSH}o z$uWjm(|_wnN<4jNG#xP_-~M7pYm9)7!NdQi3<4RYIwB5X?4FtP_hmO#vPPR4he0Yw9L&l%-l zy|~$V#tV3U9@!l>1=Z^ya4cM(xGjWMn$}<0o;+cX|2f{G*M7UNOzf#JQtrXNww5I| zzH*qex>jxY5j|~|*+{*=3mg|;9RP$hX;Th!lLH!9Wq{7iMA*BVL~iKNm~7e3nYjGw zK+5y|+=iHiIOn~!J}WZiauX(HaIE$VS4L5#LB6TV22jN)bl+y!xq9q(XKtC6d6!)A z`vFKEh`BV~p~zaHnN+=7?wVR)(;t94?J&{ORTp(Co}QNS*Q%{6@I$PF(nRY#QIQCe zRoLbpNgo`7n!9Oby*Aj`zBwn?|M?S4>e%7#;z%0Lc^|M!fI5&Oy-#5*#5BedW(lr! zHIMXW98mj@K(o*Kb+QS}iPXhIMK!M4fa~p4r7)Cg3H}*R-a}6}N96H0MwmguAcbQ^ z5d5g%*9eaZQF z>%#Hz-2V)FVtl0nFU6|+-wx?J)%ZmPI9au9_-zGSa0RlXw^6`|x|#hBc36+isAw*y+C>F2s73M$yQEpCLeIO zD^RYjSfIQ|-|wUCcXKGd1&T@+2rZ0a6M>N+l;@T4XstQP5GlWAQn>Z*H9p*LfOYwd z3nTts?cZ5rEzwC6e)QV4QOF0T^+t|e%rWTf$nnvKoYtP{pX@vbaZdP3zNrwLd&Mt; zyOBbVLOtGc-s$Jx&IHfjaplFruT8|iM+`m}hV%Y*FY#`GJQd#em-0ROrFH5eLbJX@4*+(X7^1L>ceeq<+AVpap^03h;s zk%{NJo_0Sy{g@^TD$&c)pf(3#npLXeNLu0C_gR!F)+RBFr^3VG`jcq&wSq{p14%}2 zX5SU*R4hOnpEY$KC(jF70$XM*3z)|HO0AF$w1~- z9X2(8qr7U3maC7Ke&t7E?}w2Ps1K#NZd*c8QqpnW%Fa7?i>R%=;W@*WtLkcIP`wZ8 z^_G)5rRSvKtbz4(q$Rww>uiniJ$Mtl_eH_T){DzdVT9yEOjf z*DkJq$A$lN?TTEva09#ipEj%uj(o&goCGGNLdGQ>N<kdMmUhOa*8wS>@@H?b|fel8X0nXK#r)0%8VMY&~EnzqQNv zOGWn5Xi56wGVL3P2B(~2N^=rWL^#e>UEt0dHH=--qFwG1ZXGwmY$!zc1Du8sZrS7# z5h;}7_IX0 zT*=hDGb3!*pw-QJlF{X5i6hdsCpjGZwXEG@1~WVV4?)lc;kMj;8G@!ip|$?mIS1joO)!fv5Vs zvsFbd2Q$E|(RSY4(B*0UQIl%MtCyR&ZB2&cXu}3+HP8M*wUZAZeZ!O*k`iFqEA#Z5)(1Rk3$>s9LSpl}>seL=Cpec? zmv4!hx6>N?ltU6sI8j15TBPA&0md<5`wM36`%KaW4!F=dd!60NhN_ZO8{F+$h!J(V zWfj~W=ALxBRxWg0H3FpFGCE)#6rSrcd}ZB@E4hI-S_!zGIQ-4L(L_rMo6sQ6a zk@5v7)K$X%AjB>rat8es_EfBTFY5m2{AQT}-NrnzybyUEHCWe#KL#zK7c8QIGdOo_ z-hi%|v`Ay%B(%zuEI_@Td-kH<)$7=DPlx%1 zCI6Q$%g5h9II093BZ%!Zk8(Rp2aL)qL)jFUqKOzLV3uTxmYZXCt57&GQ9|p+wgsE~|p<6Cn_!>JmgjbSXTrO+VO~kGvC` zZL8}5&-!^!mu^nw5RcH#aafndsr86KN&qWE!ZomzL>a{yX-zbP5<^ezTt3To^*}yh zlKi4eO%qu`(7~(3>Gkl*l+<*Ijp^D?at)|ZC;k^DbBh&%j0TP zwjRk#ZILjdWA3W-MXNWdhq;-+za{@^LIsmJ>zF)3DzZ$Mz=*~r(lIRhts=sr7F;5V z+Mz*HJNouJq_v4G5E{e+D*7*4A@F;8c#!)T@A_N1&c0SEFmImScX^4HQey055e=y4 zNBktlWkjpCZB^`$6(Bhjyn=;Ht9t*M1?zpjV_~u(K2y%!WO=|*@dG~d0{3zOKB8IJ zE+W={Ti-J0`$lIzGO!3nir|4wz>?F!JtDXviqnXzRXWx8Mzv4C8U%o06~LmH@qh$g z#Q{fkUlFGwfK=qFMz&xaHc1$(8^uCZ^i=fqrv+Q+$dtLW{j@h_?0I@dIeISj7h(KT z&%Tb_ZFoQFRd)1JW?@1q5x|JPOY~=K`K2d1J6sihez}PjPCWZ2BcE}SwnE>weUezZpz=dLcaeml#0wEc0Y14~L_x2MD8g*Yj{E5C5 zuisRFispH7x~uV3jzOn(01~$_b2kb!`nbBcN|(-mxmC1(7`8CmY~8xJAzry(z<`)= z7>V={Wn~EP4E_A%I0`6<`tFXPS(6ZMa|8t>8PGUTO*+8%ZoZM#F{p@baC8)sx+M8h$p z2i-2h<`_|754gCfghl)jgtMXPw4&4ZgONwdU;5PjD!~aGrr;h=l~|*m&ls{A*SIIz zk5$1OAry#Z)Sl}t>eWtEhyHqeS+hIOgtAr}E`228aR?YlcAt=yU*4WQh()N#KK~mt zzKNVLzOyr>GmQdn&3KZ5Ay`N-yf^_Pb7i~q0{}Xn_sD({!ge$1PiFL9{};I3UpVCn zg183sXCx&gEc)xcz-PDS%LilL*p3|!)#akNQ7$PVWjVwJU@jr0!W9sQgH89p z^od7{|96c_!tlY?`Yh@Q#I{JTo5gGZ-3Kt`PhC?V(9s*X@g8%%*5v4E?0oBHEeBlY2kjSE_HjlJ$hl< z<8jg1w8Or<%OSqC3PO(ZZyLH>b%=H>T|oQ!w?vGFR(wwTc_Ds-$=%#ztohV`9a;Az z7|i`wf$u+eCs#&Y4Iv)Ayr2<%Q~i$uFXqc0HBG7ns3`q!7mN6uHJZrizx#3I zEC9TFGHm~F6!s#3vfm8#ke@6hAZl1DdIOk%Ew{v}b;VexR;?O*6|C3@&k7&P)Otd~ zSb6n?jvbAgG2-urb4rGzB0_na*3XZ3T;`?)vUm*Vlx8iZ5;6_bY2YA|BwFXc?))DN zxdobsxjPyj^l0WDdai{((HpdrrwrR-^5q{z&$^D@`h5}X8^Fviqw=04A__w9U3WEA za^vT$zGeO%2YJx69kol-NOvc((O#*_Js%}Dat}i@mS8H;@r107cGW>bz&Nkmv@PvEVNPd-Mr4-kIe0AVbAr8@ohgm9;Q)x6YpT6cj&nfygihl0*5@cjvc>#TH|Hyhcv8;_Pdn^{-P@UeDYAHQf3lf(dE1@So^F!7&43orG>fevD8;@tvvuzMhgJ0Hd zU}ojW?yf%A+ZqDqoq2h@mhOBcuEizmtAbM0yK(jHpJY|hlxwnr{zNIpxP_!W=M`%f zRUH!eX*6o>E6^l#W(mGj!+K3%}{{RmDy!f6%&%x5a`XW!gE2A;83d)L<$ROI`+3y`Rf(7JeO z*l{{JT*FT-Tz4?VuzKzO`kEBM9Ya6_vHC3}3s~eC`zaXPK}V9F68s}D2fLB03tf^$ z)&vXR46H|rsP13w?O(qH-@bW(qfYeUHBaGg<7Jfc&K4vvQX}`Bupu`>#oI8G0<+!m+E+eI&LVU~7xA=~T=KvuBDEWf4kFtT_pcHuHp1HTnf#sF z0GzEq}waBl}t(Xk8F!-5&U6eE~KDk5B8Q$1A|T z*U|EoL|L<3EFlozhZ$>uvcBIN&cMSYSx~G+7@lTkowS}G*W-hStd(@=qp0gYlZR^E z*l+2>)a|m7ew8}a^`pms4*LW<%@tnV68Y#u2^}iwDa+>5ipu2V0cDbOPq_W}D6nJt zP@#)mLIJa%?d!OO%!iK? zj(&X#z2tAbofcSY2j?0%-Df|INa%rFL%1Bd&-8G%+3)3VRTSa@_p@ffD0n2%OJq0J z!4tiMNjUKirZ`a~M(HR7zOKDko&@Ir8m9)2=-j`s({gl2D!~g_feVsN{4Ua$?nip$ z;P*pHjxaLRLV3EN)FB5wc`GQ_Y{s8bH4Ncl^~7LfQg}j)kWL~z@Df_TBmow58Oifb z&qyQX&nhR9yuXw2wf|Sh+y#(e=Y;cJzbqc4zn&cQseq)nFz?8w`-Fov%Wig@F)_(` zCE#7a5EXAM^5Y;?8$@IZW{q?R)<5|o`FcDgcOhJ@6(zAI^EX77Km1w-3>qNrM~;rdKmI?;ip~BnDM2Lv->E& zhICHw2G;U&;_?B8@b$U&a$WwqXJ3E?01e&x)lIW<<>A4(w$|TG!YALBmMLp5zt`Ls zOjTE3YH_*w+}@-viiy_->`4k`&VO>dULqZ6q;CfBfGmnxQHT+Z2qf@q!NPbmWmL0& ze5E?9YAZB!v&www)Z}lh@t{uZP)jvU(oO!_%_P!{_y>%JA!)`e&r{WrXloL>SWh^z zHFvtF0k}gXEONki2*rhB#37A17!WW3VZdeG=+u|Ht&wCdDK815-8{>&ySq=fz2rQ6 zy?O7vO~1r1aS+B`R_2E7D;B~+uUWKS2d#$Q#S=F?U%PgOziLqncVF`zUR1|{_!uAB zX9ncHU^M(ySNakE8QqugzF|p;`E@e`NQXHgRvpSw4^SxmOL~_kdurPkDSDl9Q1XSp zd@x@FkDhL@zdzGIf4wFE6nLilyzlSKqIxvH;-Pv7J@C&x>Y9>0SyJ=V6b^WKhHjkA z9aLhRY%qGAU+<>?t1NaBL!5;rVWNzKT?8NRJeDIsmmaD$i2!7tKBK~{!C=dvEOl+h zm1%JG$i6qoV0-Oz^}W5q|2*M;9m4-yhVRb)+T{<3-TCgDDXm$9_jv>F0rKts3f##M zBy9a0rY3(AscC<G#Ub7{_Z6PO7S zfT?9Vks4NMNDoiy*(o{S>w|cj#%5mdrvFjc+O?2(t^r5?{o-h&hDl&NYamX*tZo#X z)2K};3dkf#(kNMv6D(vD(qyXI@30>7^eSX{k-gt?^}hR$==*Ye7y_|)ZrGx3xd+%7OabRdju9-e$`^?IsXSXC|?@Bv6I2S+%xK(s2XE+L{iwYu+v&=1e=xD`H zlpwPzMO24CUJq4GRh8il+QU86noeU)rLLK+W7y`NSUlKTw#&=&&Gz(Fj)7~Shk~lS>oR3lD{T6LlE$%sYtYPVz@Y@O5;2 zwZjzo6$ZM9JY7@T zjeo}RN1Pr_?7AUOX^rWi3TYE`nCFR*3PT;kc<>SvPO9yP;jp_`s9aLu2eFd6GqdY7 zi)DUw%bHyGG^0TejsHv6ZEM!U1q_HoXe6$f84EQnPTrT8--v7T;IaUlZn~r_%(H!k zg?WIji&MLfom~&Kth4BN*sMvy0x+#j73^iIY5OhSx0Asm)QK9kq2fWbAz zU7iQAdXamg#1&;WAj`xKCyT9qV@=6EqQIjYB zr+9ro%!|IS_ZFm%0C)j~(_fKFpF|Lpg4dHMO6iavA)cO9Ju$|$yXVW<>Rj#fW0)8C zF4Ly;5kuZTJtG>UzDn$YW&&6zS0WKWgtZr1t+W&2FC!@T|-^iN?CK|*3hDv<;{oprhhhJ*zowp;4~8x$#8xggCGDaS!(6)dud6kM~>G<-MKWchf|V z!<#GJ&$>Ck(_5GG9=)#5PebnarTkBq{wUqg`;q=c-q#DgFZbgfrx@;}NtTV~Itre-gg&VWvm^woCPBF_68QvM@rW2+c09@4KojK78#v0Xi zDb60ZJAmzS0}AtbDF#d-6fI<`+CV!hF6Hqz)5M1?1Anq1VC#X<=C4QkoX*K-uztEX z_#D&BvM787hRSai3*X3Z95AK8^4!ffNOtGNYV^`Qk=vE`Ow`H!7?eWU60HQ}e^U5VG}4l3rDTHCwDBvrC&F zd^!UQk3oCIRP1NT=u@4KzBnt_oU@1WSYx^ct8_$|4^KFXSj+eZ7Z4J7RNs97xDIG9 z?9v8m(kLE1ZOBf+0IdSGNS#5qAE?2z$wmQnMd8)sg|-H4RbG=%PVzJ_&{4@vlC^IT z63eJ400d!iS%FJQuDSL6>8tB&Yuw@MpQ8$|Prdp_t;cWah&M}FgmsU53j0h*Cj8iO zJ=`U5C9o%U8xK6zKN_%(KSKtQj*u#`jw*owPEdwb1q4aJ$HBg`y=pI!eaC}RR2VnB z{^-R@l?INg2u=D_PrLTM6yJY;6Qsi z|EMy3@x8L>>LUM|<}Q-2ByUxEYe>gtT-hDXXl;1%aM9auJUvyojC^R11iC0+Og>u; z&;c&F#h{LWi1tCw#zJm_?_(@4uLI=1t1Re0tZT@oT&bOl-!g8jbC3GD;o+;fqy|a7 zPc}+wOv`{wpbkbX1*iH20I{POOF=-!b4j^B_BoElfvOxeVwU8c)tge5nQNfX6Fx!6 zQ95B@W5)w(7FDWAiQ532DEm80@-`^L>vEmvs~8T|BB@wb76Nt!M>R$$M{=Z{3@k2? zrv(m-4=Y|lkhOcHsXnuPI5*a7Z+K~Kl;in0i;6xO9l7z*9401j=bnbj8c7R_^>g6D zIH+OJ0Yeao7L`J1B3sm|!6nXtc>1gm!KaMp(@ohL`-wS~dPC|p!MCNQDQ zUV2ngxJ8s;(Sptd7GRYXH!q4^K!{Jf55yDj8JLBY3?2|>c8wa;|7l1Svapa03oP#^ zu84%msomJBk^)AIE~l8l$GgOuGy* zF8gC5QlevRudB>TW5vc-etCs&t&XSOkR2OiiEYJ=zx0By{$h!(X=7K>?!clEHm-N1 z__sz$Me`NmVWcAul~vpcJoTAM+}oq(Y6)I+-> zQyq#6>)_oJLijS6Fb;eOM>kdhN%y9*Npu4SjHgr;K*u)o$sYkWQ&14Y;;iQ}3`GoTTaDTvhoQ6x zdqySmZ4lGgJI3ks0_w73C#C3y@jvIa4I#ykgZ_|~0ZV-LnQ~QIRi^Y(=k5xN#sU3( zidMV8k|&xt`AGKcqFGKQI&G{j699yD&SreVTo5u*q7*^@5W$PAl|-$Ci{_mOq+|Fl`);}aJG`_F0?9Ev+%tU-)XiR%QGn0x$CfGS%EoQNWG1EY7k^wqItLjo~xlylZn z8`z?~#eKf;I6e1F+kEx@74z{W6`dZ+0=XB~AT=UDw5P|6=p5E(SQ4Q2`OscH9AuiZ z`ehg&N1XL4K#G{670nCV50OY^sw@m)=Gt&jukzvilEQH~;^UBm9O`^9`xsAAxj&9Y z2gF8WV8dG~qktP0rLoQC05N6pPX@;^a**(;YHyG*(5q}s4Lgjrhl9>0?Eg1^K;23! z6j}&FS^3cBI|?SDUtHvb$i27~ZgJ)&@f6KccAO}D$*x`m7z=QA@mM^fA5)9*+r2Q-TrF_B$N1SSCcZC`Zci5{_=9Z zvORivxA&bGxWYjSJp+W)9_Bp%f>^{XXB|7hNsL{e09ge=Z#%e+P51VjImyr}!XSgN z5@S?_@WMk?M&m>$ftj|~KweGbFxJ1DQ1~3F#=&RZs=RQwWxQ}df?aytKd>Hhpfw>I zK<3_aS+0Mb-FBUN^d;qd-#a%}u%t$}H)b?|Olo1G);~aP2?>=1UO|GULSf5`HEmyl z&?ljvi|lAaz~Gk6@;OBXR2HCe^?K<*?mNFHQb)|cMT5;V|Gs1|USkF#2jpdZ>$Lpi zePuI{4QZR5iE@WYF@NdMN_Wn|HD~|u^fa>c)$}!fjFBpL2h@%C<6g)OFJ*O9zB$`V_{RDGgQi^nyC?M|3~M}Z*bPM_bk^itnX!S23+%+QHh zJQzeuM#E?r4tWEE{2r##7=>lh3MJwo4#FzrVHdaJ_zJ^mq+-D69r+AsTp#FyTstdR z>OIeB&TLR0n0=OZ89BTN%uYg~Y`g#i6d`2?PBG51(ol6g)Z)0M41!=m^z7u}v=(xv z(W*2C$pKGW=CXdawQE+gVa2BPMKxXfP4JLU*g4MJfTG9^I=?$lDG%`=wu&N^Pdp#y zD4!igs3&@rboqF@dImLEWxj-AXy!yr%_wyQvfbXp$C+pol6f?BRn2@-mLw}DK=y{LP0q>BhHdU{+OUTKHOMhh z=(Zh!{v-Y498=YHjc`|0LyVp*j6^Njwi^aj3qd3_Cmpn)S*fk*L<#2|JUgG!5zVT8 zlj-z?4y!=Z!g}6|WDi!j61Zo2QRe#}Ay!TuS+Y)_M;OIVg>W#!Di!g4tWexn;xTv;4 z&1Ib?z!bL;ZPf;Q03?}<-xD^H$F{tJ8w19iJpG3_DyoT01eN$mOi`Z3=Y+QEQ(~+g zb7*1}%e4hb){6N2D<9<^Z&jH2hN0kD#F*0V{23!A)_w+S|D_$u&R=eUXK zw&r!Ej<(=v0Jr)le@z&ud6h%%{mo;d-j6Vx^EP~O!5qUe@ceD~rxA-By(*FJH06(+ zKU@O@0sTYtud$)jPa^Zy>KUi?x^hn1mc$jxi2hMdpDq8Y!KETK1`Md^tZyYkcPs(@ z+yVUC=kCnTxnnFmlgpMpgVChKRH)P@|A_dZ5?zfcj;(5`1r_)9;AaCzc>Gc4c=)G+ zH9-p8s^E!8L0B>`%l)!Z5^~5El=AmWyd{fE$U`Mj3)2viXsh#W)dZCJJ-L7l`gXN+ zYo4WFQraI`d>DCgI!nj1%V`;BNr0Yq#m8twCckJ|;D`g5I_x!pAdFK8CkpIce{aw2 zed}FeYkt|EIQeyS59u3qu=lyBJF$bV>$1M-j8?m-_|Z4zSafHJi z{7fY9(-GX~Hts;nx*`W|R~eQT0g(X6SjsRro{DjkZ^R?V0$za`+vmpq{dzTiT}U1p z+b|y5^x3<^68bfrSXEdx{=7FgJe`=tL%dN1B*C+~!&%8EXAW93T<)VG5JevVx(}YW z`1y|DpPRw#ImfBVID`GRS=Ii$roIxgzRfz{X{i7-ML!+hs!99jc!W}?NHt&z$$Fc2 zb#M`D#5%$fI%(uj-652AK)R8?ZX3Kb1o#0CE{<%d{j331&_tUq!L+TBJvqUHhbc(L zKnAN8`<~fWK*4M2mF63dsS z+RWh%B1Y|c`Q`qnVxi2zBA6B|q%%P^hA6OAl@Z}L0>ubI5g0*<$h@taZ;%}> z3}-n)pveBVb=k5h7oK5^11DjpXN8Tpf|({wP>viVAz&j!?Kfbe;R9(y4QgcIr3+_Dmf3eUGH#)rHv^S=$`HN!f2ejLy;!vw`n9 zJA?J&D)014M?6}v`VF3$_^eSQ5$yMs*VlIvp(4H6m)SmS>;dxYSV}If$(#$->pIzrRl%ujsd}?g#n6_fIci% z@mCy37NXqY=m+vF2Z?XtMp7a28xjSmUDuG1D~Cp-wvmv z0j^A`n@WA!8sD4y^H{DRv3c1;+qPh?kbCAaE~Lf}9B^*u5Ms@Im=4;IEe3NDOXELxO|n(%xBS=A=^ z%W&*$yE{fDMOmNIfHjZzL)6N|Q}jArnYi;(cL3g?y^5uV*C-Xw4o@c`;<6pCFmXy-1jW~~(W?+}UsP{H-(7eCJ%@(15r3~z@k?+6qs0Ih6HP$2y*-Z_px{?q#;T}LGMZeqBaF%p87SA z;P;`hM4NGiG$fER#KoIZkSk=#g$9xXQAW1{o(2cnBW@37O0=2A$nY^V+nYFu-iR>% z9s<9j7F5zIx25-4oNJ0K5;~*R_>J6{H&LoI0OK<{AmzB+t3S1<-JP+>k0X{7FnnVYi|zb8-y)g^<7q;p|886)pY>gof_B$H`-G~M2fM9m^EWF79TJpKy z(Zn#1FV6Tgo^6k0Ksl@if!f}H`7hiH*nFi(_5B6Zax z$zQ3CU;wgnxrV0s0hbMQTy#Cw7F!=rbCq7Kfq<|KfKHJdE_B?&Nh)v` z3{?{a_6}TQVqB9fnkgvSZV#uP{T%IfpFpDJ6?&~1tt<4Z{*3MdC9xEzQ(nVcL73$< zQrsOn%1nO`$EyaXv=X1e6@`rVF8Jr?+-uaFvZZU&W6rb_%2DfaWE&Xxw#2CJGI+L< zxAoIQU6y0(cQZ#Z8Y1dHmORZYj<{8Ke3p^HW-(%+y1kn*hQU%fgVzVihO)Z%LSxX- zGtlvjq_ong&e@L`1U2GfyQ83p0LR|B=u-3FI7Pf-ah<-k%(@s)OHx$#+Ci>ps@7C4_FM0 zFUdJutF5|=D+6M=j}xs)D@a$|ZVFav7L>1E(S_}h#`8+RZ-zXe1!YagRy}3k4E`br zQsFd_3n9oSCHINM@RneG`*dX5)Sxpxu{IjC)(NA}=zL5pXXl6wNKgfOwl`wx7 zYaZ$q0rhNZQ|m>uB9<_!^21stGYo2CWH7KX`^(>Tq@~DP6MeqlWZ2ZfcB86lKHFsH z(`=J9a{Ru|Q!YQ*1)<1|gWA-OK*y1v60sXBA~WH7ow2u#OEpRx6fK03RX!DLRT4Ct~SS>m6MwH<=?8UN#I*hsJxAz~GPtRoT%38_LlL%J}?ZE7z6 zKTMrta3)dPtz+AECZ5>N#CT%cb|!ja+qN;`#LmRFZQD*x-tT+QsZ-V1-L?BiS9MkI zz1MxMC9GrB6Pgd1yqE@<4Zt+_Gp)aHed?HDov?g$@S3v}FCGDAA@S_rcNR%IR@;o? zf}vt>m36Sb9U(JD?H`E-{wAPI>E}jAG?#QZ`E4-CG^$GTk}7*^T#(TW`TIm)JNp zaaQaoZH$mBBq_rV?RXAf%{(UZFLj3r6d4JYp_2#+(70ufVcHGzYrC}{@!H26C6=Kl zx+R*5R7}6W*TvL<+3ah?rWatFosLabZAUVHFk+D4Ask$0Jg^Sy9>vNLtGzA1Uu5+k zD~&M^Km-MoS+!@L&4Dh=LDXG8wUp!){7>+Z<+3n=*J`@Ww0`JD-t`qk6ydr@Is!{*tj{bi_U z%ca-+J`$^q-D>ApWy;RT5dr49*D%Af(hi;Py@}vknF)B))u>&sbA2Brcs<9`?_4MI z5+E53=)v0y^Kwzrj;KWwV4|RW2(FJ_`!4nZBkzv6>ca8FdEoDOG`#8_-6g)9{Of7Q z4hW4=#YGtu0-Z;jiXvH*!fI7zQ9?)fTVHXMqi^j9W!!BGQ8J*LjI=Q+M*gNBz#H=4Lma)Kjhe?1uQ= zL?G---qalbFk6S%$UtpV0`Fz*(hmhHaAVrMf1)r3$Hya}-}?IqEO0 zOph#h-wF@U-%Fcv&%cYgCr(2bvOfYhPB&+cb^fu|)I8Zc@wJTHZ2uTi=j86{l1jLJ zk&AizZnloxOv{-`;&iHRRGq8TM}Kq{_Kk`^Y{Oip*`CjD3vXA&AXz78KU5|Vsy%W% zxmj;j+C64oUY-9NdYws}&@rw=89^;j$u|;t;16o%d=soBamjXg1EtFNSxs9f=|o~@ z+)#k3Xo@JD!fOseDLk8>wLehaJLi;`IxpxupSxJqgpfWT317;ey2>n5E3yuUDw>Bt zk4r~iLcOaLv_*v)i%QUtw*Rr&|Hi+B{dV)^m{WCm>A-@%A0RU9VBL5viiej~6c0O5 zv;deSGT^CgJAo4~Uht-?XzyaT`K_<6(}IMKYwiqWY%qm#md$$^bWrkdCKCR!o_0WrQ&Z1*$D-{!pbpy~0(_%geDQi_0eL3l7}x z@n4|pnH|zwc^pU|8H+qxA#E>YL`H^~wtjQ4?XKf?He8+Xwvu z@P4vi}BkxL_=7@XyB8OIkGP*fh*u z+_%k;$o=r4Vkbs#V@>YV>Awr~o1h!1KK6zngs6+aeVZ^mRR3r+QZ%`E^ejb}cKTq- zJZ%J_W^6qI-}y^EUV&jZ=2+xt`-WKcnA}V624>i0;avKMkyr1!4rD&JZh6>iX+KVR zP*h~RE$^7)ZxGfrMa-_~J^}g^p-DQ;MI?lbZqtKdOg=WVWoTWJvj=%D=j`(rMc2I` zLzLZ-5{W1*DUIFFDbXnUJ^?se$$P6u8_8ljeVh$F$ zmfz)5GTwTpcP~pvv;hv-8FZ7a$x%$@VKY z*EE7p=EPktMd1RkgO?*at``MOjZg2HTi@_r?w^{f8vUW047;Wk&53VcY3tlZ{mdud z29NS2;wB{`?j9xU7gruauGn&PnP5I)Qv9C`Hv$IzmIfMuY9(mo^q3hiXaq_B{;=R6JRR0ii~P93m*TLM()=hab~9 zFz~c@sH-a{vaMn&Zc?Llm#I`yEmqnPjU@`lSm)~Lz5Fd(k_s& zv33mPZHj1Z_}wlqDa4rMHdaG@>EYvRTGvSWKPBR=8i7Hty_pbEBS>{q$b0539mNKb zZN^GYYGIr^iNt%ysx^d_L_J#kHJA-0LP3|`Iz)Gw#3LmIF z{Rx_2WC{aI1C4z?m|9MSKOD%{{D#i&!9h9KJTweg!EI+OioHmq)gCd9yAsn=Lgi}( zG^;Rquk)REJh8LSv^q2!A!mP5D8?Z}2H=?Jbgezx3G|N6X?1!&C-25Lp7v-F9^%6O z<#<3*yCFp8Oi&<(i$B-LsR4C@REUa(cxQcCm(EC>k&@dB#7*(Z@D$w#%@w5uz$^)K zp%b#B<;5J*O8)eU3m_-nQ+>DgEv})?PrdlTWAV>xAERzAOb9=;-R4NOfC~hn@S2kd zMR8rb@<{$Y6COO4A00spE+9Q3LSc-dQCK`W$PnwM87?+bSH|7T?OLO7^bo3AO%0-A z7gMe37IR>@Fd6YD?i{|f4BLwCLaYKP+i#>0n>~8X5=zOR!cMRWGI8IJ4FKsn3x&mg zD80h(Fg49u_V9yQPQeYi!5rEM7)VwvSP9BYnB}c$FtN-Vgxo!6HohvF+84Iv*oLsC zHSCMXrgghz2>B$S=BJiEPRT2pNt9k2bH2R^e!y!U{3v2N(J`LWB=f`8e9$H_c82Zx zHtLn=5D9}O6BQjLD{c`UrK}+q(Gnd~O!MOLHKeh~t2*`(ay0v+wr6=-w=)&1Qu_>5u{36oWX$)B-8CyFJosi+w1r3({nu6Sgd{IOdM zOQA&sxj_x2CI39J$Ra+a?r-N#)MsN@cwY9X(Bi?0X*oul#Gye_R3TH_LQ4(pRh<|4 zlo7<+6PT)>x3Re@>GM%MxJ|Io7&=IIa_2=lx}x_e;)138XQB&6e~Dw12O1}W#msEQ ziJ8K0b!rQes1eZ1vDa^;PUlv*M#bRU=Iu;%4|3fu9p$)2>N=Q2F}VRZ0{& zsLeVzyU%*9LHi94$*K{U?qP>VBAsdY-`S|&%se#yoR_W3?N7Wr4sT`-rPlH;SF0vD zx;2P_1sSU8oX+u6?0@Qv!kLJi?e@=42Q^d7?`KHa`QX2lfTY0%35sKw51{bHiWFQ9 z#xQfu{3f6{F)5++cHm#9AI^yn*wJ=Ri=|YmMKRZYn2`TMli+Eo=>wopBsVI4 zRYPy+Y#SrF8k^9q%Wp?G@R#=k zYd;U^H%|f6NTL=&sX&Hwg+P*wHPnvYeWb08{9~jo$T8T-gR*x1icR-%4#(v8KUZ~X zPV-wfbB3$R7w`aq9M^l|qq#jIZBOuEdK~A})6aG6$91x!%*xAKa6VFhsL`={U|8?bYMVQ7cT!5>Nfz| z@QzT}J7J$#*) zZ=E9M%ukXSAIF+3hoI9k#V!MJi>&LS+eX49)JOS=eK`6OO%}yo7CjFRXMZA8>B892@Dj8)X$1xOiHCb^$g=BqMv@3Z$2q3q&tZKnDtdF)Dn~Vi&zvHi@XCcE3f`=5rjWjFz zaIM!CGY8w;9%#~c8r}Kg-R9s|(n~=*V$(J?e z1rq;+5vmLVa8qSaR5${RgA`H6y~Kq5tal3f>7_4{SmUM1LIO0DPX{q6a0)Goj3yF0 zG4r;>;iDFid-U2tJlEPJkJ=XNlMdPBHFDlLJqnrPIDY8rjQjz4VYCww=T(2%tyfXy zy;=w$4X|!rH3u1UMn-4jVLvLDG5;sG;(?F#d7#6BJnWt~P+vd&QGSM6)8}vJGrqaO z%XbV=BWT7kHggSJ#8vKtPvA3O8|3gTNtO4}Lf2@5wQ+AB($dfU@L>h120G7vEbC_* zQ)PRY#n`8SI`^<2QwRMejryislReVX;%1#4>8P^xgx!O$Ie8I+LBr|y49g+{n|a1K z*_-jIy1I8%-LjYf%F?JD7@xmsI;MgR0^_MEIf)QY=zcoo1u0!Jg;dL;kO?hN^d(BA z4IPj4v-Fhqk)1`fZ_{W;U!KU>HjUrc!M)GYqQmmJGp?vrZ6mamEYJQ@^Bfl7tRslm znv^aHG!_r`1LvUktSRc1bv!R8Zpuq23ixVcQmHY#1sCdyXWW&h{mlj9arJ!y50FPq`91hvsX1{9_r@x@d2$ zelzB46$2{c`O}$yE`rIP8HaFIN-Vu$8QzSGGHBp_&Q_jMfoXm7`o2kn)Cd-IZ1B4x z2=e*czV*Cv1CJ+7;al!5KM9(96iX1V3BdWU;GM^%WM4$SXmrr2hBt(YqO9Z20J9gt zEC5xtZt~8Dzz8ICMk**zU7)M^0nyn*6}k``gG2|-oBTQ>H}=;Y6H0lx71wj2aY|qc zHMjyChH|l$f3Y>Aokrp4&&ZJo&w|n9(<}G!mPbGLpPF6J_5Y0-;4+_d1Sr;`9yCZD z$U(r3;uS;8t)l&GXfQaPG0dt@_rkrnt4|t&0tp^z%U_92@?_)%ot_*_HlnZGPL{mbVM)u*m?BA{kVfFh zJ(BhXc_CfS*5M9Q6t{x`7dZ(Ij40wD6x&SV@#TK;O0tG{vP8lYA}XhgE3DE{wbVHN z#u2Fh`pR((-F%NSi7(7z-H2_GWBBdP&58MPpioQP(nC-tS1084a*_cRp;ry7m00~> zdmyr#o)0$O;i!jLYQ(ereTR9v^@2XoqfzjpBfr_9kNggi|D3=D%r&g(d^|V*`Dls1k zuXrWS1ao~MJTeT{UU>@Dl!c<_S&JKw&_JQ`3B*ugm=D#8HwB0T`meuC$7gu(1A@NY zz3v74u`HVgvD&x!G`{tDGC@Qs<~&I#U%oU5$r!A5>Ti8s#W3ilKLShMdLbM6@%!sO zC040h-)&=Tpi>z5BKt%Ii~Q`<+o2ccCee-+30s8KF26}69($_wPO;2kTVs7 zC=I&=G(v<%f*?VY(Y*|JiuWoLGf?TkQN-74d}|5$ecK9XQo$K13ELNb?H4+(u{|o^ zIy!hqw5RDV$=Mk`4bDSjdi81PkA;@@o zTo*i_WLRlfUC4JhIsJzqI{;!1ZAr)m$TfJ;npK*x>U7YgeYNg^-=^hq%t;6RKm9p^ z?Y~EcjPXWagEczYAc@)b95$1SVrlC(xeYsgTA)ld(f{_o1$(_r2=ArAytT%3#q;|V zYq9xO4mjqekeU6}7KEw?N6d{g{^RvdWrUSx3<1udtPmXG@iuWVm`(r;UF*2+|5II4 zUr2&+{~&IX)HBw58$3u~)M}NybjxMRtORF%(yGY7F;G>AT)b>>=<`Opq%_FPOEF2mJ))Eeu%Xm=xE zR>Wg_A~x4lY0wD4K|u|oELnmo#OYi@J)xEpx?JEI!^OE~K$)uK`y7M`N<)E-7$ree z-nTUvcQAxh9rQ%&f0rNUvgGhEyQH_;zG6VQp8gQg11N|W!p=MFMI9}p8nYwS=jt=~ z5A}f%1u4;}4?rB9eQu8K41Ui4Q=Vh#0%bAS3Rwp%!*^m|OxB;2?Oo4Z^{(rhd~DLJ z+0t2me&l{Wb_EmTb;@`1A_aAv7Ib=cXl^uIe6lvZ#-v{9ltl~{ z%DwbQvR3{yvzwA=7Td#UGTmX}9onEiLuk*R-ZtNknLkko;E}Yi*me~?(GWN?v;hcM z8luE9TumkpvI=tdMIb}j8_^q<2<FIJ- zdFa(dkM{!#`V}Ih@{>sC{}D6gVQ^p>n>5b+$iT7PkLhZI=E(8C%GA(fB(Wnpb1oqL zRn!DvMWklYvJX-chh~J#E3zol$)ah6PxsJ&KJ?YY@iMlg2uENtiZFtX8^p5(#c@7Q zb3SNIH0|TmP>NB1arbg|nc;3dHqHHfk>CCu`?=QblXDR=S${2MYz0_fa>)SEhuU~l zuG!ee|9KEP%>HhZSF&`OUBv;CtWya#Q1i%>2k!m6c=~ekk|2^*SP&Kh>w|U4QLY2) zxY?FDj7AkN9snb2p|b2~j8f)A#Mfkl(BCRS)MXz5G@kzj+uRGJuY`C(#OmA`CPNul zq(+VFT+_s(tLtj9Y-3fqqk|8$>L}E(7zcNwX_S^OL(5|GhnG&~s8>&=Rh$49X4hbC zIvpy^cv2P#RBPI}%qdMInd9>EnuCQoeEJ+m_I(TOe(39d0s5XkeSVyWez(3Zk$pcx zzqhZ0s}ErPm6LbYmi>W?LwC}fnk&|2D2LsQp z?H#C(t--)>^Bq2Uq>k6h`XZd&z=He-;dXS{$4f)5?%IivvDF*8yEJ3{Zb#_`M{daK znh9tU9PZhIXf=p%3e4i-O#`N>#xPlkXmVm_tCNTIct)qjhmIM`W~Bi!6g+5KjmuPz zFtLGLb}gC(v9A*)vQ;K0sI#hs8E?y>8ipv>qH%+96$drR{;cBpYnMTJ&FZj-Kl3p% zC4`iRN!6n_tBz|~J-K>MM#tN`vL)}t?~^s}J#JlJZ{0VU-CydTPLJJRRKADAUT;e! zC({+hJi+Z%S&-dU>!(9U)&}V{x|&CHh7S#Hi#kdhuRhHA_iu;qF%x%6nVV{vWIb7+ zj#kR1MzwYP9l!e?fKCr%VTsv*Mq)pr6r*%-1RH zGo}wi``0W}gzlLi^RamjVl4m#bvUzpJQuQhr#+m)u};t7jn6-(R-jdbTeHT+9mmx)ywY z{CXG@{6hA_VK0B zNLJR4OT`tA@>K8_&%@alo8;7qfF*~Y-$9-ub%L62CH^{>_{t5QNzuU-Pfoxa%WHAu zp`3E$ODHn{(GJn3&up3xQtXVN5)C9$DG~Q0>ZqRI9IE9hMKlMjnxe*Y{|%JB;H>;; zF=9IngDo`>8U80sYZXCY3My9YCH&Uu3yM5>*K;D#XX7SmndFfFeL4JJma0RFeOro?MDJa-UKiU&$TZ0*%0AuX<8J}Rx)KG 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%0DGEv0%Q@uk8njT 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 z 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 literal 0 HcmV?d00001 From 29dcff0f34b99f940966140fe635db8aa8b2c2df Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Wed, 18 Nov 2020 14:32:32 +0100 Subject: [PATCH 18/21] spark complains about missing classes, so here they are again --- dhp-workflows/dhp-graph-provision/pom.xml | 10 ---------- .../model/SerializableSolrInputDocument.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java diff --git a/dhp-workflows/dhp-graph-provision/pom.xml b/dhp-workflows/dhp-graph-provision/pom.xml index 38b575f3e..1547056b9 100644 --- a/dhp-workflows/dhp-graph-provision/pom.xml +++ b/dhp-workflows/dhp-graph-provision/pom.xml @@ -14,16 +14,6 @@ org.apache.spark spark-core_2.11 - - - org.slf4j - slf4j-api - - - org.slf4j - jul-to-slf4j - - org.apache.spark diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java new file mode 100644 index 000000000..e8d910e8c --- /dev/null +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java @@ -0,0 +1,19 @@ +package eu.dnetlib.dhp.oa.provision.model; + +import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.SolrInputField; + +import java.util.HashMap; +import java.util.Map; + +public class SerializableSolrInputDocument extends SolrInputDocument { + + public SerializableSolrInputDocument() { + super(new HashMap<>()); + } + + public SerializableSolrInputDocument(Map fields) { + super(fields); + } + +} From d9e07a242b8bb7f43231b8b62ec7e2fa2e5525ec Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Wed, 18 Nov 2020 14:34:55 +0100 Subject: [PATCH 19/21] extended XmlIndexingJob to accept an optional parameter: outputPath. When present, forces the job to write its output on the specified HDFS location --- .../dhp/oa/provision/XmlIndexingJob.java | 85 +++++++++++-------- .../model/SerializableSolrInputDocument.java | 3 + .../provision/input_params_update_index.json | 6 ++ .../dhp/oa/provision/oozie_app/workflow.xml | 1 + .../eu/dnetlib/dhp/oa/provision/SolrTest.java | 11 +-- .../dhp/oa/provision/XmlIndexingJobTest.java | 59 +++++++++++-- 6 files changed, 117 insertions(+), 48 deletions(-) diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java index c51dc3b58..f7a1ee49d 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJob.java @@ -1,8 +1,31 @@ package eu.dnetlib.dhp.oa.provision; -import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; +import com.lucidworks.spark.util.SolrSupport; +import eu.dnetlib.dhp.application.ArgumentApplicationParser; +import eu.dnetlib.dhp.oa.provision.model.SerializableSolrInputDocument; +import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; +import eu.dnetlib.dhp.oa.provision.utils.StreamingInputDocumentFactory; +import eu.dnetlib.dhp.utils.ISLookupClientFactory; +import eu.dnetlib.dhp.utils.saxon.SaxonTransformerFactory; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.io.Text; +import org.apache.solr.common.SolrInputDocument; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.sql.Encoders; +import org.apache.spark.sql.SaveMode; +import org.apache.spark.sql.SparkSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; @@ -10,29 +33,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Optional; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.apache.commons.io.IOUtils; -import org.apache.hadoop.io.Text; -import org.apache.solr.common.SolrInputDocument; -import org.apache.spark.SparkConf; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.spark.rdd.RDD; -import org.apache.spark.sql.SparkSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.lucidworks.spark.util.SolrSupport; - -import eu.dnetlib.dhp.application.ArgumentApplicationParser; -import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; -import eu.dnetlib.dhp.oa.provision.utils.StreamingInputDocumentFactory; -import eu.dnetlib.dhp.utils.ISLookupClientFactory; -import eu.dnetlib.dhp.utils.saxon.SaxonTransformerFactory; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import static eu.dnetlib.dhp.common.SparkSessionSupport.runWithSparkSession; public class XmlIndexingJob { @@ -48,6 +49,8 @@ public class XmlIndexingJob { private int batchSize; + private String outputPath; + private SparkSession spark; public static void main(String[] args) throws Exception { @@ -72,12 +75,17 @@ public class XmlIndexingJob { final String format = parser.get("format"); log.info("format: {}", format); + final String outputPath = Optional.ofNullable(parser.get("outputPath")) + .orElse(null); + log.info("outputPath: {}", outputPath); + final Integer batchSize = parser.getObjectMap().containsKey("batchSize") ? Integer.valueOf(parser.get("batchSize")) : DEFAULT_BATCH_SIZE; log.info("batchSize: {}", batchSize); final SparkConf conf = new SparkConf(); + conf.registerKryoClasses(new Class[] { SerializableSolrInputDocument.class }); runWithSparkSession( conf, @@ -86,15 +94,16 @@ public class XmlIndexingJob { final String isLookupUrl = parser.get("isLookupUrl"); log.info("isLookupUrl: {}", isLookupUrl); final ISLookupClient isLookup = new ISLookupClient(ISLookupClientFactory.getLookUpService(isLookupUrl)); - new XmlIndexingJob(spark, inputPath, format, batchSize).run(isLookup); + new XmlIndexingJob(spark, inputPath, format, batchSize, outputPath).run(isLookup); }); } - public XmlIndexingJob(SparkSession spark, String inputPath, String format, Integer batchSize) { + public XmlIndexingJob(SparkSession spark, String inputPath, String format, Integer batchSize, String outputPath) { this.spark = spark; this.inputPath = inputPath; this.format = format; this.batchSize = batchSize; + this.outputPath = outputPath; } public void run(ISLookupClient isLookup) throws ISLookUpException, TransformerException { @@ -116,15 +125,23 @@ public class XmlIndexingJob { final JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext()); - RDD docs = sc - .sequenceFile(inputPath, Text.class, Text.class) - .map(t -> t._2().toString()) - .map(s -> toIndexRecord(SaxonTransformerFactory.newInstance(indexRecordXslt), s)) - .map(s -> new StreamingInputDocumentFactory(version, dsId).parseDocument(s)) - .rdd(); + JavaRDD docs = sc + .sequenceFile(inputPath, Text.class, Text.class) + .map(t -> t._2().toString()) + .map(s -> toIndexRecord(SaxonTransformerFactory.newInstance(indexRecordXslt), s)) + .map(s -> new StreamingInputDocumentFactory(version, dsId).parseDocument(s)); - final String collection = ProvisionConstants.getCollectionName(format); - SolrSupport.indexDocs(zkHost, collection, batchSize, docs); + if (StringUtils.isNotBlank(outputPath)) { + spark.createDataset( + docs.map(s -> new SerializableSolrInputDocument(s)).rdd(), + Encoders.kryo(SerializableSolrInputDocument.class)) + .write() + .mode(SaveMode.Overwrite) + .parquet(outputPath); + } else { + final String collection = ProvisionConstants.getCollectionName(format); + SolrSupport.indexDocs(zkHost, collection, batchSize, docs.rdd()); + } } protected static String toIndexRecord(Transformer tr, final String record) { diff --git a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java index e8d910e8c..05b39ab6f 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java +++ b/dhp-workflows/dhp-graph-provision/src/main/java/eu/dnetlib/dhp/oa/provision/model/SerializableSolrInputDocument.java @@ -6,6 +6,9 @@ import org.apache.solr.common.SolrInputField; import java.util.HashMap; import java.util.Map; +/** + * Wrapper class needed to make the SolrInputDocument compatible with the Kryo serialization mechanism. + */ public class SerializableSolrInputDocument extends SolrInputDocument { public SerializableSolrInputDocument() { diff --git a/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/input_params_update_index.json b/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/input_params_update_index.json index 3396020e0..3169648fb 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/input_params_update_index.json +++ b/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/input_params_update_index.json @@ -22,5 +22,11 @@ "paramLongName": "batchSize", "paramDescription": "size of the batch of documents sent to solr", "paramRequired": false + }, + { + "paramName": "o", + "paramLongName": "outputPath", + "paramDescription": "path on hdfs activating an alternative output for the SolrInputDocuments", + "paramRequired": false } ] diff --git a/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/oozie_app/workflow.xml b/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/oozie_app/workflow.xml index e2b74b9aa..ee636b68e 100644 --- a/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-graph-provision/src/main/resources/eu/dnetlib/dhp/oa/provision/oozie_app/workflow.xml @@ -638,6 +638,7 @@ --isLookupUrl${isLookupUrl} --format${format} --batchSize${batchSize} + --outputPath${outputPath} diff --git a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java index 426c8e678..186cb964a 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java +++ b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/SolrTest.java @@ -54,13 +54,14 @@ public abstract class SolrTest { miniCluster.uploadConfigSet(configDir.toPath(), CONFIG_NAME); // override settings in the solrconfig include - // System.setProperty("solr.tests.maxBufferedDocs", "100000"); - // System.setProperty("solr.tests.maxIndexingThreads", "-1"); - // System.setProperty("solr.tests.ramBufferSizeMB", "100"); + System.setProperty("solr.tests.maxBufferedDocs", "100000"); + System.setProperty("solr.tests.maxIndexingThreads", "-1"); + System.setProperty("solr.tests.ramBufferSizeMB", "100"); // use non-test classes so RandomizedRunner isn't necessary - // System.setProperty("solr.tests.mergeScheduler", "org.apache.lucene.index.ConcurrentMergeScheduler"); - // System.setProperty("solr.directoryFactory", "solr.RAMDirectoryFactory"); + System.setProperty("solr.tests.mergeScheduler", "org.apache.lucene.index.ConcurrentMergeScheduler"); + System.setProperty("solr.directoryFactory", "solr.RAMDirectoryFactory"); + System.setProperty("solr.lock.type", "single"); log.info(new ConfigSetAdminRequest.List().process(miniCluster.getSolrClient()).toString()); log diff --git a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java index 2d62fc0af..b855f4d88 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java +++ b/dhp-workflows/dhp-graph-provision/src/test/java/eu/dnetlib/dhp/oa/provision/XmlIndexingJobTest.java @@ -1,26 +1,33 @@ package eu.dnetlib.dhp.oa.provision; -import java.io.IOException; -import java.net.URI; - +import eu.dnetlib.dhp.oa.provision.model.SerializableSolrInputDocument; +import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; +import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; import org.apache.commons.io.IOUtils; import org.apache.hadoop.io.Text; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrInputField; import org.apache.solr.common.params.CommonParams; import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaPairRDD; import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.MapFunction; +import org.apache.spark.sql.Dataset; +import org.apache.spark.sql.Encoders; import org.apache.spark.sql.SparkSession; +import org.dom4j.io.SAXReader; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import eu.dnetlib.dhp.oa.provision.utils.ISLookupClient; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException; -import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService; +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; @ExtendWith(MockitoExtension.class) public class XmlIndexingJobTest extends SolrTest { @@ -58,6 +65,7 @@ public class XmlIndexingJobTest extends SolrTest { SparkConf conf = new SparkConf(); conf.setAppName(XmlIndexingJobTest.class.getSimpleName()); + conf.registerKryoClasses(new Class[] { SerializableSolrInputDocument.class }); conf.setMaster("local[1]"); conf.set("spark.driver.host", "localhost"); @@ -78,7 +86,7 @@ public class XmlIndexingJobTest extends SolrTest { } @Test - public void testXmlIndexingJob() throws Exception { + public void testXmlIndexingJob_onSolr() throws Exception { String inputPath = "src/test/resources/eu/dnetlib/dhp/oa/provision/xml"; @@ -87,13 +95,46 @@ public class XmlIndexingJobTest extends SolrTest { .sequenceFile(inputPath, Text.class, Text.class) .count(); - new XmlIndexingJob(spark, inputPath, FORMAT, batchSize).run(isLookupClient); + new XmlIndexingJob(spark, inputPath, FORMAT, batchSize, null).run(isLookupClient); Assertions.assertEquals(0, miniCluster.getSolrClient().commit().getStatus()); QueryResponse rsp = miniCluster.getSolrClient().query(new SolrQuery().add(CommonParams.Q, "*:*")); - Assertions.assertEquals(nRecord, rsp.getResults().getNumFound()); + Assertions.assertEquals(nRecord, rsp.getResults().getNumFound(), + "the number of indexed records should be equal to the number of input records"); + } + + @Test + public void testXmlIndexingJob_saveOnHDFS() throws Exception { + final String ID_XPATH = "//header/*[local-name()='objIdentifier']"; + + String inputPath = "src/test/resources/eu/dnetlib/dhp/oa/provision/xml"; + + final JavaPairRDD xmlRecords = JavaSparkContext + .fromSparkContext(spark.sparkContext()) + .sequenceFile(inputPath, Text.class, Text.class); + long nRecord = xmlRecords.count(); + long xmlIdUnique = xmlRecords + .map(t -> t._2().toString()) + .map(s -> new SAXReader().read(new StringReader(s)).valueOf(ID_XPATH)) + .distinct().count(); + Assertions.assertEquals(nRecord, xmlIdUnique, "IDs should be unique among input records"); + + final String outputPath = workingDir.resolve("outputPath").toAbsolutePath().toString(); + new XmlIndexingJob(spark, inputPath, FORMAT, batchSize, outputPath).run(isLookupClient); + + final Dataset solrDocs = spark.read() + .load(outputPath) + .as(Encoders.kryo(SerializableSolrInputDocument.class)); + long docIdUnique = solrDocs.map((MapFunction) doc -> { + final SolrInputField id = doc.getField("__indexrecordidentifier"); + return id.getFirstValue().toString(); + }, Encoders.STRING()) + .distinct() + .count(); + Assertions.assertEquals(xmlIdUnique, docIdUnique, "IDs should be unique among the output records"); + } } From 5218718e8b8363694fc8abfacf3eeff57e5d3539 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Wed, 18 Nov 2020 15:00:41 +0100 Subject: [PATCH 20/21] updated set of fields from the MDFormatDSResourceType on PROD --- .../test/resources/eu/dnetlib/dhp/oa/provision/fields.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/fields.xml b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/fields.xml index f74da5d07..1f5cf7b81 100644 --- a/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/fields.xml +++ b/dhp-workflows/dhp-graph-provision/src/test/resources/eu/dnetlib/dhp/oa/provision/fields.xml @@ -105,7 +105,7 @@ - + @@ -123,7 +123,8 @@ - + + From e503271abe61f51c77a171ac391e09c468c76042 Mon Sep 17 00:00:00 2001 From: Claudio Atzori Date: Thu, 19 Nov 2020 10:41:38 +0100 Subject: [PATCH 21/21] fixed notification workflow name --- .../dhp/broker/oa/notifications_only/oozie_app/workflow.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhp-workflows/dhp-broker-events/src/main/resources/eu/dnetlib/dhp/broker/oa/notifications_only/oozie_app/workflow.xml b/dhp-workflows/dhp-broker-events/src/main/resources/eu/dnetlib/dhp/broker/oa/notifications_only/oozie_app/workflow.xml index f629c2101..879c0d349 100644 --- a/dhp-workflows/dhp-broker-events/src/main/resources/eu/dnetlib/dhp/broker/oa/notifications_only/oozie_app/workflow.xml +++ b/dhp-workflows/dhp-broker-events/src/main/resources/eu/dnetlib/dhp/broker/oa/notifications_only/oozie_app/workflow.xml @@ -1,4 +1,4 @@ - +