From c5b3a668901c4622d580a177258fd2bd6d2747f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20G=C3=B3mez?= Date: Fri, 24 Aug 2018 10:59:04 +0200 Subject: [PATCH] [release] release 0.4.1 (#957) ### Release 0.4.1 * [#877] added support for property value null (#908) fixes #877 * [#856] property pushdown hbase (#906) fixes #856 * [#864] Change examples to use csv (#905) fixes #864 * [#494] Add Set support to PropertyValue (#916) fixes #494 * [#888] Minor changes to Tuple-related functions. (#912) fixes #888 * [#779] Add code coverage for Gradoop (#914) fixes #779 * [#702] Add support for graphs without edges to TLFDataSource (#921) fixes #702 * [#909] Remove Flink dependency for store instance (#918) fixes #909 * [#876] added print for logical graph and graph collection (#913) fixes #876 * [#857] logical predicate chaining hbase (#920) fixes #857 * [#926] added argLine to maven properties (fix ide testing bug) (#929) fixes #926 * [#794] include new benchmark classes (#904) fixes #794 * [#312] example program for aggregation (#925) fixes #312 * [#901] Add SamplingConstants, AggregationConstants (#934) fixed #901 * [#935] Add tests for containment functions (#941) fixes #935 * [#900] Refactor sampling tests. (#907) fixes #900 * [#936] Generalized RollUp and DrillDown (#939) fixes #936 * [#947] Fix PageRank wrapper and add a test. (#949) fixes #947 * [#942] graph density computation for sampling evaluation (#946) fixes #942 * [#954] prepare minor release (#955) fixes #954 --- README.md | 4 +- dev-support/store/hbase_table_layout | 44 +- gradoop-checkstyle/pom.xml | 2 +- gradoop-common/pom.xml | 6 +- .../model/impl/properties/Properties.java | 33 +- .../model/impl/properties/PropertyValue.java | 89 +- .../impl/properties/PropertyValueUtils.java | 45 + .../org/gradoop/common/GradoopTestUtils.java | 23 +- .../impl/properties/PropertyValueTest.java | 144 +- .../properties/PropertyValueUtilsTest.java | 1922 +++++++++-------- gradoop-examples/pom.xml | 6 +- .../benchmark/cypher/CypherBenchmark.java | 245 +++ .../org/gradoop/benchmark/cypher/Queries.java | 104 + .../benchmark/cypher/package-info.java | 19 + .../benchmark/grouping/GroupingBenchmark.java | 16 +- .../benchmark/patternmatching/Queries.java | 9 - .../sna/SocialNetworkAnalyticsExample.java | 251 +++ .../benchmark/sna/functions/CountFilter.java | 34 + .../benchmark/sna/functions/package-info.java | 19 + .../gradoop/benchmark/sna/package-info.java | 19 + .../benchmark/subgraph/SubgraphBenchmark.java | 215 ++ .../benchmark/subgraph/package-info.java | 19 + .../org/gradoop/examples/AbstractRunner.java | 145 +- .../aggregation/AggregationExample.java | 99 + .../AddPropertyMeanAgeToGraphHead.java | 40 + .../functions/AggregateListOfNames.java | 54 + .../aggregation/functions/package-info.java | 19 + .../examples/aggregation/package-info.java | 19 + .../examples/biiig/FrequentLossPatterns.java | 22 +- .../examples/grouping/GroupingRunner.java | 13 +- .../org/gradoop/examples/io/DOTExample.java | 32 +- .../patternmatching/CypherExample.java | 9 +- .../PatternMatchingRunner.java | 6 +- .../gradoop/examples/sna/SNABenchmark1.java | 15 +- .../gradoop/examples/sna/SNABenchmark2.java | 30 +- .../sampling/RandomEdgeSamplingRunner.java | 2 + ...ndomLimitedDegreeVertexSamplingRunner.java | 9 +- .../RandomNonUniformVertexSamplingRunner.java | 4 +- .../RandomVertexEdgeSamplingRunner.java | 9 +- ...andomVertexNeighborhoodSamplingRunner.java | 26 +- .../sampling/RandomVertexSamplingRunner.java | 2 + .../statistics/GraphDensityRunner.java | 65 + .../statistics/SamplingStatisticsRunner.java | 46 + .../sampling/statistics/package-info.java | 19 + .../resources/data/csv/foodbroker/edges.csv | 1892 ++++++++++++++++ .../data/csv/foodbroker/metadata.csv | 32 + .../data/csv/foodbroker/vertices.csv | 804 +++++++ .../sna/statistics/distinct_edge_properties | 1 + .../distinct_edge_properties_by_label | 2 + .../statistics/distinct_source_vertex_count | 1 + ...distinct_source_vertex_count_by_edge_label | 5 + .../statistics/distinct_target_vertex_count | 1 + ...distinct_target_vertex_count_by_edge_label | 5 + .../sna/statistics/distinct_vertex_properties | 7 + .../distinct_vertex_properties_by_label | 8 + .../data/csv/sna/statistics/edge_count | 1 + .../csv/sna/statistics/edge_count_by_label | 5 + ...edge_count_by_source_vertex_and_edge_label | 5 + ...edge_count_by_target_vertex_and_edge_label | 5 + .../incoming_vertex_degree_distribution | 4 + .../outgoing_vertex_degree_distribution | 4 + .../data/csv/sna/statistics/vertex_count | 1 + .../csv/sna/statistics/vertex_count_by_label | 3 + .../sna/statistics/vertex_degree_distribution | 4 + gradoop-flink/pom.xml | 6 +- .../algorithms/gelly/pagerank/PageRank.java | 3 +- .../pagerank/functions/PageRankResultKey.java | 31 + .../io/impl/csv/metadata/MetaDataParser.java | 86 +- .../flink/io/impl/dot/DOTDataSink.java | 4 +- .../flink/io/impl/gdl/GDLConsoleOutput.java | 70 + .../flink/io/impl/gdl/GDLDataSink.java | 89 + .../gradoop/flink/io/impl/gdl/GDLEncoder.java | 331 +++ .../gdl/functions/GraphTransactionsToGDL.java | 55 + .../io/impl/gdl/functions/package-info.java | 19 + .../flink/io/impl/gdl/package-info.java | 19 + .../flink/io/impl/tlf/TLFDataSource.java | 15 +- .../impl/tlf/functions/DictionaryEntry.java | 3 +- .../functions/GraphTransactionFromText.java | 133 +- .../flink/model/api/epgm/GraphCollection.java | 10 + .../flink/model/api/epgm/LogicalGraph.java | 56 +- .../model/api/epgm/LogicalGraphOperators.java | 49 +- .../impl/functions/tuple/Project3To0.java | 1 - .../impl/functions/tuple/Project4To0And1.java | 3 +- .../impl/functions/tuple/SwitchPair.java | 9 +- .../model/impl/functions/tuple/Value2Of3.java | 2 + .../impl/functions/tuple/ValueInTuple1.java | 3 + .../functions/tuple/ValueOfWithCount.java | 2 +- .../functions/containment/HasEdgeLabel.java | 7 +- .../functions/containment/HasVertexLabel.java | 7 +- .../functions/count/EdgeCount.java | 7 +- .../functions/count/VertexCount.java | 7 +- .../functions/max/MaxProperty.java | 8 +- .../functions/min/MinProperty.java | 8 +- .../functions/sum/SumProperty.java | 7 +- .../model/impl/operators/drilling/Drill.java | 202 +- .../impl/operators/drilling/DrillDown.java | 64 +- .../drilling/{DrillUp.java => RollUp.java} | 70 +- .../DrillDownTransformation.java | 2 +- .../transformations/DrillTransformation.java | 2 +- ...rmation.java => RollUpTransformation.java} | 18 +- .../CollectionEqualityByGraphIds.java | 6 +- .../sampling/RandomEdgeSampling.java | 28 +- .../RandomLimitedDegreeVertexSampling.java | 19 +- .../RandomNonUniformVertexSampling.java | 31 +- .../sampling/RandomVertexEdgeSampling.java | 53 +- .../RandomVertexNeighborhoodSampling.java | 45 +- .../sampling/RandomVertexSampling.java | 11 +- .../operators/sampling/SamplingAlgorithm.java | 68 + .../EdgesWithSampledVerticesFilter.java | 19 +- ...ilterVerticesWithDegreeOtherThanGiven.java | 18 +- .../sampling/functions/Neighborhood.java | 63 +- .../sampling/functions/VertexDegree.java | 4 +- .../sampling/statistics/GraphDensity.java | 51 + .../SamplingEvaluationConstants.java | 37 + .../functions/CalculateDensity.java | 54 + .../statistics/functions/package-info.java | 19 + .../sampling/statistics/package-info.java | 19 + .../impl/operators/subgraph/Subgraph.java | 6 +- .../tostring/api/VertexToString.java | 6 +- .../gelly/pagerank/PageRankTest.java | 54 + .../flink/io/impl/csv/CSVDataSinkTest.java | 1 - .../flink/io/impl/csv/CSVDataSourceTest.java | 1 - .../flink/io/impl/csv/CSVTestBase.java | 28 + .../flink/io/impl/gdl/GDLDataSinkTest.java | 31 + .../flink/io/impl/tlf/TLFDataSinkTest.java | 61 +- .../flink/io/impl/tlf/TLFDataSourceTest.java | 23 + .../aggregation/AggregationTest.java | 85 +- .../aggregation/ApplyAggregationTest.java | 59 + .../impl/operators/drilling/DrillTest.java | 187 +- .../ParametrizedTestForGraphSampling.java | 249 ++- .../sampling/RandomEdgeSamplingTest.java | 105 +- ...RandomLimitedDegreeVertexSamplingTest.java | 147 +- .../RandomNonUniformVertexSamplingTest.java | 59 +- .../RandomVertexEdgeSamplingTest.java | 70 +- .../RandomVertexNeighborhoodSamplingTest.java | 72 +- .../sampling/RandomVertexSamplingTest.java | 60 +- .../sampling/statistics/GraphDensityTest.java | 49 + .../resources/data/csv/expected/expected.gdl | 2 +- .../resources/data/csv/input/metadata.csv | 2 +- .../resources/data/csv/input/vertices.csv | 2 +- .../csv/input_extended_properties/edges.csv | 2 +- .../input_extended_properties/metadata.csv | 6 +- .../input_extended_properties/vertices.csv | 4 +- .../data/csv/input_indexed/metadata.csv | 2 +- .../csv/input_indexed/vertices/A/data.csv | 2 +- .../data/tlf/io_test_string_without_edges.tlf | 6 + gradoop-store/gradoop-accumulo/pom.xml | 6 +- .../storage/config/GradoopAccumuloConfig.java | 77 +- .../impl/accumulo/AccumuloEPGMStore.java | 43 +- .../accumulo/handler/AccumuloEdgeHandler.java | 1 - .../handler/AccumuloGraphHandler.java | 1 - .../accumulo/handler/AccumuloRowHandler.java | 16 +- .../handler/AccumuloVertexHandler.java | 24 +- .../impl/accumulo/io/AccumuloBase.java | 34 +- .../impl/accumulo/io/AccumuloDataSink.java | 51 +- .../impl/accumulo/io/AccumuloDataSource.java | 26 +- .../io/inputformats/BaseInputFormat.java | 2 +- .../io/outputformats/BaseOutputFormat.java | 141 -- .../io/outputformats/EdgeInOutputFormat.java | 68 - .../io/outputformats/EdgeOutOutputFormat.java | 68 - .../io/outputformats/EdgeOutputFormat.java | 66 - .../io/outputformats/ElementOutputFormat.java | 119 + .../outputformats/GraphHeadOutputFormat.java | 66 - .../io/outputformats/VertexOutputFormat.java | 66 - .../io/outputformats/package-info.java | 3 +- .../client/ClientClosableIterator.java | 3 +- .../filter/api/AccumuloElementFilter.java | 12 +- .../filter/calculate/{AND.java => And.java} | 12 +- .../filter/calculate/{NOT.java => Not.java} | 14 +- .../filter/calculate/{OR.java => Or.java} | 12 +- .../predicate/query/AccumuloQueryHolder.java | 5 + .../storage/utils/AccumuloFilters.java | 12 +- .../impl/accumulo/AccumuloStoreTestBase.java | 12 +- .../impl/accumulo/AccumuloTestSuite.java | 23 +- .../impl/accumulo/basic/StoreTest.java | 93 +- .../storage/impl/accumulo/io/IOBasicTest.java | 31 +- .../io/source/IOEdgePredicateTest.java | 15 +- .../io/source/IOElementIdRangeTest.java | 14 +- .../io/source/IOGraphPredicateTest.java | 12 +- .../io/source/IOVertexPredicateTest.java | 18 +- .../predicate/StoreBasicPredicateTest.java | 19 +- .../predicate/StoreIdsPredicateTest.java | 6 +- .../predicate/StoreLabelPredicateTest.java | 14 +- .../predicate/StorePropPredicateTest.java | 12 +- gradoop-store/gradoop-hbase/pom.xml | 6 +- .../storage/config/GradoopHBaseConfig.java | 68 +- .../storage/impl/hbase/HBaseEPGMStore.java | 6 +- .../storage/impl/hbase/api/EdgeHandler.java | 10 +- .../impl/hbase/api/ElementHandler.java | 15 +- .../impl/hbase/api/GraphHeadHandler.java | 10 +- .../storage/impl/hbase/api/VertexHandler.java | 10 +- .../impl/hbase/constants/HBaseConstants.java | 8 +- .../impl/hbase/filter/HBaseFilterUtils.java | 50 - .../impl/hbase/handler/HBaseEdgeHandler.java | 12 +- .../hbase/handler/HBaseElementHandler.java | 69 +- .../handler/HBaseGraphElementHandler.java | 4 +- .../hbase/handler/HBaseGraphHeadHandler.java | 12 +- .../hbase/handler/HBaseVertexHandler.java | 9 +- .../storage/impl/hbase/io/HBaseBase.java | 20 +- .../storage/impl/hbase/io/HBaseDataSink.java | 12 +- .../impl/hbase/io/HBaseDataSource.java | 49 +- .../io/inputformats/BaseTableInputFormat.java | 12 +- .../io/inputformats/EdgeTableInputFormat.java | 8 +- .../GraphHeadTableInputFormat.java | 8 +- .../inputformats/VertexTableInputFormat.java | 8 +- .../hbase/iterator/HBaseEdgeIterator.java | 7 +- .../hbase/iterator/HBaseGraphIterator.java | 7 +- .../iterator/HBasePropertyValueWrapper.java | 122 -- .../hbase/iterator/HBaseVertexIterator.java | 7 +- .../predicate/filter/HBaseFilterUtils.java | 256 +++ .../filter/api/HBaseElementFilter.java | 27 +- .../filter/api/package-info.java | 2 +- .../hbase/predicate/filter/calculate/And.java | 97 + .../hbase/predicate/filter/calculate/Not.java | 73 + .../hbase/predicate/filter/calculate/Or.java | 97 + .../filter/calculate/package-info.java | 19 + .../filter/impl/HBaseLabelIn.java | 30 +- .../filter/impl/HBaseLabelReg.java | 24 +- .../filter/impl/HBasePropEquals.java | 52 + .../filter/impl/HBasePropLargerThan.java | 53 + .../predicate/filter/impl/HBasePropReg.java | 53 + .../filter/impl/package-info.java | 2 +- .../{ => predicate}/filter/package-info.java | 2 +- .../gradoop/storage/utils/HBaseFilters.java | 109 + .../gradoop/storage/utils/package-info.java | 19 + .../impl/hbase/GradoopHBaseTestBase.java | 34 +- .../impl/hbase/HBaseGraphStoreTest.java | 425 +++- .../filter/api/HBaseElementFilterTest.java | 79 - .../hbase/io/HBaseDataSinkSourceTest.java | 372 +++- .../filter/impl/HBaseLabelInTest.java | 4 +- .../filter/impl/HBaseLabelRegTest.java | 4 +- .../filter/impl/HBasePropEqualsTest.java | 127 ++ .../filter/impl/HBasePropLargerThanTest.java | 135 ++ .../filter/impl/HBasePropRegTest.java | 73 + .../resources/data/gdl/social_network.gdl | 6 +- .../src/test/resources/log4j-test.properties | 2 +- gradoop-store/gradoop-store-api/pom.xml | 6 +- .../api/EPGMGraphPredictableOutput.java | 6 +- .../common/config/GradoopStoreConfig.java | 83 +- .../common/predicate/filter/impl/PropReg.java | 2 +- gradoop-store/pom.xml | 2 +- pom.xml | 29 +- 242 files changed, 10780 insertions(+), 3367 deletions(-) create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/CypherBenchmark.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/Queries.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/sna/SocialNetworkAnalyticsExample.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/CountFilter.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/sna/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/SubgraphBenchmark.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/examples/aggregation/AggregationExample.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AddPropertyMeanAgeToGraphHead.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AggregateListOfNames.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/examples/aggregation/package-info.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/GraphDensityRunner.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/SamplingStatisticsRunner.java create mode 100644 gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/package-info.java create mode 100644 gradoop-examples/src/main/resources/data/csv/foodbroker/edges.csv create mode 100644 gradoop-examples/src/main/resources/data/csv/foodbroker/metadata.csv create mode 100644 gradoop-examples/src/main/resources/data/csv/foodbroker/vertices.csv create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties_by_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count_by_edge_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count_by_edge_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties_by_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_source_vertex_and_edge_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_target_vertex_and_edge_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/incoming_vertex_degree_distribution create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/outgoing_vertex_degree_distribution create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count_by_label create mode 100644 gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_degree_distribution create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/functions/PageRankResultKey.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLConsoleOutput.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLDataSink.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLEncoder.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/GraphTransactionsToGDL.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/package-info.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/package-info.java rename gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/{DrillUp.java => RollUp.java} (50%) rename gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/{DrillUpTransformation.java => RollUpTransformation.java} (81%) create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/SamplingAlgorithm.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensity.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/SamplingEvaluationConstants.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/CalculateDensity.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/package-info.java create mode 100644 gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/package-info.java create mode 100644 gradoop-flink/src/test/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRankTest.java create mode 100644 gradoop-flink/src/test/java/org/gradoop/flink/io/impl/gdl/GDLDataSinkTest.java create mode 100644 gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensityTest.java create mode 100644 gradoop-flink/src/test/resources/data/tlf/io_test_string_without_edges.tlf delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/BaseOutputFormat.java delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeInOutputFormat.java delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutOutputFormat.java delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutputFormat.java create mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/ElementOutputFormat.java delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/GraphHeadOutputFormat.java delete mode 100644 gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/VertexOutputFormat.java rename gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/{AND.java => And.java} (88%) rename gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/{NOT.java => Not.java} (82%) rename gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/{OR.java => Or.java} (88%) delete mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/HBaseFilterUtils.java delete mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBasePropertyValueWrapper.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/HBaseFilterUtils.java rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/api/HBaseElementFilter.java (74%) rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/api/package-info.java (92%) create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/And.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Not.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Or.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/package-info.java rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/impl/HBaseLabelIn.java (56%) rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/impl/HBaseLabelReg.java (63%) create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEquals.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThan.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropReg.java rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/impl/package-info.java (91%) rename gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/package-info.java (92%) create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/HBaseFilters.java create mode 100644 gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/package-info.java delete mode 100644 gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilterTest.java rename gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/impl/HBaseLabelInTest.java (95%) rename gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/{ => predicate}/filter/impl/HBaseLabelRegTest.java (95%) create mode 100644 gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEqualsTest.java create mode 100644 gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThanTest.java create mode 100644 gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropRegTest.java diff --git a/README.md b/README.md index 5a7614e7aed5..2bddb99d911f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/apache/maven.svg?label=License)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/badge/Maven_Central-0.4.0-blue.svg?label=Maven%20Central)](http://search.maven.org/#search%7Cga%7C1%7Cgradoop) +[![Maven Central](https://img.shields.io/badge/Maven_Central-0.4.1-blue.svg?label=Maven%20Central)](http://search.maven.org/#search%7Cga%7C1%7Cgradoop) [![Build Status](https://travis-ci.org/dbs-leipzig/gradoop.svg?branch=master)](https://travis-ci.org/dbs-leipzig/gradoop) ## Gradoop: Distributed Graph Analytics on Hadoop @@ -108,7 +108,7 @@ Stable: org.gradoop gradoop-flink - 0.4.0 + 0.4.1 ``` diff --git a/dev-support/store/hbase_table_layout b/dev-support/store/hbase_table_layout index 1f403ad080d7..db326520f29e 100644 --- a/dev-support/store/hbase_table_layout +++ b/dev-support/store/hbase_table_layout @@ -1,39 +1,45 @@ GraphData (table 'graph_heads') -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- row | cf | cq | timestamp | value -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- | m | l | | {label} - {id} *-------------*-------------------------*---------------*--------------------- - | p | {property key} | | {property value} -----------*-------------*-------------------------*---------------*--------------------- + {id} *-------------*-------------------------*---------------*----------------------- + | p_type | {property key} | | {property type byte} + *-------------*-------------------------*---------------*----------------------- + | p_value | {property key} | | {property value} +----------*-------------*-------------------------*---------------*----------------------- VertexData (table 'vertices') -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- row | cf | cq | timestamp | value -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- | m | l | | {label} - {id} *-------------*-------------------------*---------------*--------------------- + {id} *-------------*-------------------------*---------------*----------------------- | m | g | | {graph id} - *-------------*-------------------------*---------------*--------------------- - | p | {property key} | | {property value} -----------*-------------*-------------------------*---------------*--------------------- + *-------------*-------------------------*---------------*----------------------- + | p_type | {property key} | | {property type byte} + *-------------*-------------------------*---------------*----------------------- + | p_value | {property key} | | {property value} +----------*-------------*-------------------------*---------------*----------------------- EdgeData (table 'edges') -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- row | cf | cq | timestamp | value -----------*-------------*-------------------------*---------------*--------------------- +----------*-------------*-------------------------*---------------*----------------------- | m | l | | {label} - *-------------*-------------------------*---------------*--------------------- + *-------------*-------------------------*---------------*----------------------- | m | g | | {graph id} - {id} *-------------*-------------------------*---------------*--------------------- + {id} *-------------*-------------------------*---------------*----------------------- | m | s | | {source vertex id} - *-------------*-------------------------*---------------*--------------------- + *-------------*-------------------------*---------------*----------------------- | m | t | | {varget vertex id} - *-------------*-------------------------*---------------*--------------------- - | p | {property key} | | {property value} -----------*-------------*-------------------------*---------------*--------------------- + *-------------*-------------------------*---------------*----------------------- + | p_type | {property key} | | {property type byte} + *-------------*-------------------------*---------------*----------------------- + | p_value | {property key} | | {property value} +----------*-------------*-------------------------*---------------*----------------------- diff --git a/gradoop-checkstyle/pom.xml b/gradoop-checkstyle/pom.xml index 92431753067f..622f430f7b6d 100644 --- a/gradoop-checkstyle/pom.xml +++ b/gradoop-checkstyle/pom.xml @@ -5,7 +5,7 @@ org.gradoop gradoop-parent - 0.5.0-SNAPSHOT + 0.4.1 gradoop-checkstyle diff --git a/gradoop-common/pom.xml b/gradoop-common/pom.xml index 845e95be34e3..af4445fe7dd8 100644 --- a/gradoop-common/pom.xml +++ b/gradoop-common/pom.xml @@ -5,7 +5,7 @@ org.gradoop gradoop-parent - 0.5.0-SNAPSHOT + 0.4.1 gradoop-common @@ -104,6 +104,10 @@ + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/Properties.java b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/Properties.java index e8427e31e7b3..38b97ec64e83 100644 --- a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/Properties.java +++ b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/Properties.java @@ -23,6 +23,7 @@ import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -257,13 +258,28 @@ public int hashCode() { return properties != null ? properties.hashCode() : 0; } + /** + * {@inheritDoc} + */ @Override public Iterator iterator() { - return properties.entrySet().stream() - .map(e -> Property.create(e.getKey(), e.getValue())) - .collect(Collectors.toList()).iterator(); + return toList().iterator(); + } + + /** + * Returns a list of properties. + * + * @return List of properties + */ + public List toList() { + return properties.entrySet().stream() + .map(e -> Property.create(e.getKey(), e.getValue())) + .collect(Collectors.toList()); } + /** + * {@inheritDoc} + */ @Override public void write(DataOutputView outputView) throws IOException { outputView.writeInt(properties.size()); @@ -274,6 +290,10 @@ public void write(DataOutputView outputView) throws IOException { } } + + /** + * {@inheritDoc} + */ @Override public void read(DataInputView inputView) throws IOException { int propertyCount = inputView.readInt(); @@ -290,10 +310,13 @@ public void read(DataInputView inputView) throws IOException { } } + /** + * {@inheritDoc} + */ @Override public String toString() { - return properties.entrySet().stream() - .map(e -> Property.create(e.getKey(), e.getValue()).toString()) + return toList().stream() + .map(Property::toString) .collect(Collectors.joining(",")); } } diff --git a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValue.java b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValue.java index dcf16e1c33a4..acf31cada760 100644 --- a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValue.java +++ b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValue.java @@ -36,12 +36,14 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.ArrayList; import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Collections; +import java.util.Set; /** * Represents a single property value in the EPGM. @@ -115,6 +117,10 @@ public class PropertyValue implements Value, Serializable, Comparable} for {@link java.lang.Short} */ public static final transient byte TYPE_SHORT = 0x0e; + /** + * {@code } for {@link java.util.Set} + */ + public static final transient byte TYPE_SET = 0x0f; /** * Value offset in byte @@ -317,6 +323,14 @@ public boolean isTime() { public boolean isDateTime() { return rawBytes[0] == TYPE_DATETIME; } + /** + * True, if the wrapped value is of type {@code Set}. + * + * @return true, if {@code Set} value + */ + public boolean isSet() { + return rawBytes[0] == TYPE_SET; + } /** * True, if the wrapped value is a subtype of {@code Number}. @@ -351,7 +365,8 @@ public Object getObject() { isDate() ? getDate() : isTime() ? getTime() : isDateTime() ? getDateTime() : - null; + isSet() ? getSet() : + null; } /** * Returns the wrapped value as {@code boolean}. @@ -542,6 +557,36 @@ public LocalDateTime getDateTime() { return DateTimeSerializer.deserializeDateTime( Arrays.copyOfRange(rawBytes, OFFSET, DateTimeSerializer.SIZEOF_DATETIME + OFFSET)); } + /** + * Returns the wrapped Set as {@code Set}. + * + * @return {@code Set} value + */ + public Set getSet() { + PropertyValue entry; + + Set set = new HashSet<>(); + + ByteArrayInputStream byteStream = new ByteArrayInputStream(rawBytes); + DataInputStream inputStream = new DataInputStream(byteStream); + DataInputView inputView = new DataInputViewStreamWrapper(inputStream); + + try { + if (inputStream.skipBytes(OFFSET) != OFFSET) { + throw new RuntimeException("Malformed entry in PropertyValue Set"); + } + while (inputStream.available() > 0) { + entry = new PropertyValue(); + entry.read(inputView); + + set.add(entry); + } + } catch (IOException e) { + throw new RuntimeException("Error reading PropertyValue"); + } + + return set; + } //---------------------------------------------------------------------------- // Setter @@ -551,7 +596,7 @@ public LocalDateTime getDateTime() { * Sets the given value as internal value if it has a supported type. * * @param value value - * @throws UnsupportedTypeException + * @throws UnsupportedTypeException if the type of the Object is not supported */ public void setObject(Object value) { if (value == null) { @@ -584,6 +629,8 @@ public void setObject(Object value) { setTime((LocalTime) value); } else if (value instanceof LocalDateTime) { setDateTime((LocalDateTime) value); + } else if (value instanceof Set) { + setSet((Set) value); } else { throw new UnsupportedTypeException(value.getClass()); } @@ -770,6 +817,30 @@ public void setDateTime(LocalDateTime dateTime) { Bytes.putBytes(rawBytes, OFFSET, valueBytes, 0, valueBytes.length); } + /** + * Sets the wrapped value as {@code Set} value. + * + * @param set value + */ + public void setSet(Set set) { + int size = set.stream().mapToInt(PropertyValue::byteSize).sum() + OFFSET; + + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(size); + DataOutputStream outputStream = new DataOutputStream(byteStream); + DataOutputView outputView = new DataOutputViewStreamWrapper(outputStream); + + try { + outputStream.write(TYPE_SET); + for (PropertyValue entry : set) { + entry.write(outputView); + } + } catch (IOException e) { + throw new RuntimeException("Error writing PropertyValue"); + } + + this.rawBytes = byteStream.toByteArray(); + } + //---------------------------------------------------------------------------- // Util //---------------------------------------------------------------------------- @@ -804,6 +875,7 @@ private static Map getTypeMap() { map.put(TYPE_DATE, LocalDate.class); map.put(TYPE_TIME, LocalTime.class); map.put(TYPE_DATETIME, LocalDateTime.class); + map.put(TYPE_SET, Set.class); return Collections.unmodifiableMap(map); } @@ -871,7 +943,9 @@ public int compareTo(PropertyValue o) { result = this.getTime().compareTo(o.getTime()); } else if (this.isDateTime() && o.isDateTime()) { result = this.getDateTime().compareTo(o.getDateTime()); - } else if (this.isMap() || o.isMap() || this.isList() || o.isList()) { + } else if (this.isMap() || o.isMap() || + this.isList() || o.isList() || + this.isSet() || o.isSet()) { throw new UnsupportedOperationException(String.format( "Method compareTo() is not supported for %s, %s", this.getClass(), o.getClass())); } else { @@ -926,7 +1000,7 @@ public void write(DataOutputView outputView) throws IOException { } outputView.writeByte(type); // Write length for types with a variable length. - if (isString() || isBigDecimal() || isMap() || isList()) { + if (isString() || isBigDecimal() || isMap() || isList() || isSet()) { // Write length as an int if the "large" flag is set. if ((type & FLAG_LARGE) == FLAG_LARGE) { outputView.writeInt(rawBytes.length - OFFSET); @@ -946,7 +1020,8 @@ public void read(DataInputView inputView) throws IOException { // Apply bitmask to get the actual type. byte type = (byte) (~FLAG_LARGE & typeByte); // dynamic type? - if (type == TYPE_STRING || type == TYPE_BIG_DECIMAL || type == TYPE_MAP || type == TYPE_LIST) { + if (type == TYPE_STRING || type == TYPE_BIG_DECIMAL || type == TYPE_MAP || + type == TYPE_LIST || type == TYPE_SET) { // read length if ((typeByte & FLAG_LARGE) == FLAG_LARGE) { length = inputView.readInt(); diff --git a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValueUtils.java b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValueUtils.java index 89d7bc7c086a..3fc8e4d4df41 100644 --- a/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValueUtils.java +++ b/gradoop-common/src/main/java/org/gradoop/common/model/impl/properties/PropertyValueUtils.java @@ -18,6 +18,7 @@ import org.gradoop.common.exceptions.UnsupportedTypeException; import java.math.BigDecimal; +import java.util.Arrays; import static com.google.common.base.Preconditions.checkNotNull; @@ -611,4 +612,48 @@ private static float floatValue(PropertyValue value, int type) { } } } + + /** + * Byte utilities. + */ + public static class Bytes { + + /** + * Get the raw byte representation of a {@link PropertyValue} instance without the type byte as prefix. + * + * @param value the {@link PropertyValue} to extract the bytes + * @return a byte array containing the value without type information + */ + public static byte[] getRawBytesWithoutType(PropertyValue value) { + return Arrays.copyOfRange(value.getRawBytes(), 1, value.getRawBytes().length); + } + + /** + * Get the type byte of a {@link PropertyValue} instance. It's the first one of the + * raw representation of a PropertyValue. + * + * @param value the {@link PropertyValue} to extract the type byte + * @return the type byte as array + */ + public static byte[] getTypeByte(PropertyValue value) { + byte[] typeByte = new byte[1]; + typeByte[0] = value.getRawBytes()[0]; + return typeByte; + } + + /** + * Creates a {@link PropertyValue} instance by concatenating the byte representations + * of the type and the value. + * + * @param typeByte a byte array containing only one byte representing the value type + * @param valueBytes a byte array representing the property value + * @return the resulting {@link PropertyValue} + */ + public static PropertyValue createFromTypeValueBytes(byte[] typeByte, byte[] valueBytes) { + byte[] validValue = new byte[valueBytes.length + 1]; + validValue[0] = typeByte[0]; + System.arraycopy(valueBytes, 0, validValue, 1, valueBytes.length); + return PropertyValue.fromRawBytes(validValue); + } + } } diff --git a/gradoop-common/src/test/java/org/gradoop/common/GradoopTestUtils.java b/gradoop-common/src/test/java/org/gradoop/common/GradoopTestUtils.java index e998cdde5514..ed47c2b62fb1 100644 --- a/gradoop-common/src/test/java/org/gradoop/common/GradoopTestUtils.java +++ b/gradoop-common/src/test/java/org/gradoop/common/GradoopTestUtils.java @@ -48,9 +48,11 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import static org.junit.Assert.*; @@ -78,6 +80,9 @@ public class GradoopTestUtils { public static final String KEY_c = "keyc"; public static final String KEY_d = "keyd"; public static final String KEY_e = "keye"; + public static final String KEY_f = "keyf"; + public static final String KEY_g = "keyg"; + public static final String KEY_h = "keyh"; public static final Object NULL_VAL_0 = null; public static final boolean BOOL_VAL_1 = true; @@ -93,7 +98,8 @@ public class GradoopTestUtils { public static final LocalDate DATE_VAL_b = LocalDate.now(); public static final LocalTime TIME_VAL_c = LocalTime.now(); public static final LocalDateTime DATETIME_VAL_d = LocalDateTime.now(); - public static final short SHORT_VAL_e = (short)23; + public static final short SHORT_VAL_e = (short)23; + public static final Set SET_VAL_f = new HashSet<>(); private static Comparator ID_COMPARATOR = new EPGMIdentifiableComparator(); @@ -126,6 +132,20 @@ public class GradoopTestUtils { LIST_VAL_a.add(PropertyValue.create(DATETIME_VAL_d)); LIST_VAL_a.add(PropertyValue.create(SHORT_VAL_e)); + SET_VAL_f.add(PropertyValue.create(NULL_VAL_0)); + SET_VAL_f.add(PropertyValue.create(BOOL_VAL_1)); + SET_VAL_f.add(PropertyValue.create(INT_VAL_2)); + SET_VAL_f.add(PropertyValue.create(LONG_VAL_3)); + SET_VAL_f.add(PropertyValue.create(FLOAT_VAL_4)); + SET_VAL_f.add(PropertyValue.create(DOUBLE_VAL_5)); + SET_VAL_f.add(PropertyValue.create(STRING_VAL_6)); + SET_VAL_f.add(PropertyValue.create(BIG_DECIMAL_VAL_7)); + SET_VAL_f.add(PropertyValue.create(GRADOOP_ID_VAL_8)); + SET_VAL_f.add(PropertyValue.create(DATE_VAL_b)); + SET_VAL_f.add(PropertyValue.create(TIME_VAL_c)); + SET_VAL_f.add(PropertyValue.create(DATETIME_VAL_d)); + SET_VAL_f.add(PropertyValue.create(SHORT_VAL_e)); + SUPPORTED_PROPERTIES = Maps.newTreeMap(); SUPPORTED_PROPERTIES.put(KEY_0, NULL_VAL_0); SUPPORTED_PROPERTIES.put(KEY_1, BOOL_VAL_1); @@ -142,6 +162,7 @@ public class GradoopTestUtils { SUPPORTED_PROPERTIES.put(KEY_c, TIME_VAL_c); SUPPORTED_PROPERTIES.put(KEY_d, DATETIME_VAL_d); SUPPORTED_PROPERTIES.put(KEY_e, SHORT_VAL_e); + SUPPORTED_PROPERTIES.put(KEY_f, SET_VAL_f); } /** diff --git a/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueTest.java b/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueTest.java index aa122af21b46..2fd6a2598acf 100644 --- a/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueTest.java +++ b/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueTest.java @@ -34,6 +34,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; import static org.gradoop.common.GradoopTestUtils.*; import static org.gradoop.common.model.impl.properties.PropertyValue.create; @@ -129,30 +131,34 @@ public void testCreate() throws Exception { p = create(BIG_DECIMAL_VAL_7); assertTrue(p.isBigDecimal()); assertEquals(BIG_DECIMAL_VAL_7, p.getBigDecimal()); - //GradoopId + // GradoopId p = create(GRADOOP_ID_VAL_8); assertTrue(p.isGradoopId()); assertEquals(GRADOOP_ID_VAL_8, p.getGradoopId()); - //Map + // Map p = create(MAP_VAL_9); assertTrue(p.isMap()); assertEquals(MAP_VAL_9, p.getMap()); - //List + // List p = create(LIST_VAL_a); assertTrue(p.isList()); assertEquals(LIST_VAL_a, p.getList()); - //Date + // Date p = create(DATE_VAL_b); assertTrue(p.isDate()); assertEquals(DATE_VAL_b, p.getDate()); - //Time + // Time p = create(TIME_VAL_c); assertTrue(p.isTime()); assertEquals(TIME_VAL_c, p.getTime()); - //DateTime + // DateTime p = create(DATETIME_VAL_d); assertTrue(p.isDateTime()); assertEquals(DATETIME_VAL_d, p.getDateTime()); + // Set + p = create(SET_VAL_f); + assertTrue(p.isSet()); + assertEquals(SET_VAL_f, p.getSet()); } @Test @@ -206,24 +212,28 @@ public void testSetAndGetObject() throws Exception { p.setObject(LIST_VAL_a); assertTrue(p.isList()); assertEquals(LIST_VAL_a, p.getObject()); - //Date + // Date p.setObject(DATE_VAL_b); assertTrue(p.isDate()); assertEquals(DATE_VAL_b, p.getDate()); - //Time + // Time p.setObject(TIME_VAL_c); assertTrue(p.isTime()); assertEquals(TIME_VAL_c, p.getTime()); - //DateTime + // DateTime p.setObject(DATETIME_VAL_d); assertTrue(p.isDateTime()); assertEquals(DATETIME_VAL_d, p.getDateTime()); + // Set + p.setObject(SET_VAL_f); + assertTrue(p.isSet()); + assertEquals(SET_VAL_f, p.getSet()); } @Test(expected = UnsupportedTypeException.class) public void testSetObjectWithUnsupportedType() { PropertyValue p = new PropertyValue(); - p.setObject(new HashSet<>()); + p.setObject(new PriorityQueue<>()); } @Test @@ -244,6 +254,7 @@ public void testIsNull() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -264,6 +275,7 @@ public void testIsBoolean() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -297,6 +309,7 @@ public void testIsShort() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -330,6 +343,7 @@ public void testIsInt() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -363,6 +377,7 @@ public void testIsLong() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -396,6 +411,7 @@ public void testIsFloat() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -429,6 +445,7 @@ public void testIsDouble() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -462,6 +479,7 @@ public void testIsString() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -495,6 +513,7 @@ public void testIsBigDecimal() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -528,6 +547,7 @@ public void testIsGradoopId() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -561,6 +581,7 @@ public void testIsMap() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -594,6 +615,7 @@ public void testIsList() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -627,6 +649,7 @@ public void testIsDate() throws Exception { assertTrue(p.isDate()); assertFalse(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -660,6 +683,7 @@ public void testIsTime() throws Exception { assertFalse(p.isDate()); assertTrue(p.isTime()); assertFalse(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -675,7 +699,6 @@ public void testSetTime() throws Exception { assertEquals(TIME_VAL_c, p.getTime()); } - @Test public void testIsDateTime() throws Exception { PropertyValue p = PropertyValue.create(DATETIME_VAL_d); @@ -694,6 +717,7 @@ public void testIsDateTime() throws Exception { assertFalse(p.isDate()); assertFalse(p.isTime()); assertTrue(p.isDateTime()); + assertFalse(p.isSet()); } @Test @@ -709,6 +733,40 @@ public void testSetDateTime() throws Exception { assertEquals(DATETIME_VAL_d, p.getDateTime()); } + @Test + public void testIsSet() throws Exception { + PropertyValue p = PropertyValue.create(SET_VAL_f); + assertFalse(p.isNull()); + assertFalse(p.isBoolean()); + assertFalse(p.isShort()); + assertFalse(p.isInt()); + assertFalse(p.isLong()); + assertFalse(p.isFloat()); + assertFalse(p.isDouble()); + assertFalse(p.isString()); + assertFalse(p.isBigDecimal()); + assertFalse(p.isGradoopId()); + assertFalse(p.isMap()); + assertFalse(p.isList()); + assertFalse(p.isDate()); + assertFalse(p.isTime()); + assertFalse(p.isDateTime()); + assertTrue(p.isSet()); + } + + @Test + public void testGetSet() throws Exception { + PropertyValue p = PropertyValue.create(SET_VAL_f); + assertEquals(SET_VAL_f, p.getSet()); + } + + @Test + public void testSetSet() throws Exception { + PropertyValue p = new PropertyValue(); + p.setSet(SET_VAL_f); + assertEquals(SET_VAL_f, p.getSet()); + } + @Test public void testIsNumber() throws Exception { PropertyValue p = PropertyValue.create(SHORT_VAL_e); @@ -742,6 +800,8 @@ public void testIsNumber() throws Exception { assertFalse(p.isNumber()); p = PropertyValue.create(DATETIME_VAL_d); assertFalse(p.isNumber()); + p = PropertyValue.create(SET_VAL_f); + assertFalse(p.isNumber()); } @Test @@ -808,7 +868,14 @@ public void testEqualsAndHashCode() throws Exception { LocalDateTime dateTime3 = LocalDateTime.of(date3, time3); validateEqualsAndHashCode(create(dateTime1), create(dateTime2), create(dateTime3)); - } + + Set set1 = new HashSet<>(); + set1.add(PropertyValue.create("bar")); + Set set2 = new HashSet<>(); + set2.add(PropertyValue.create("bar")); + Set set3 = new HashSet<>(); + set3.add(PropertyValue.create("baz")); + validateEqualsAndHashCode(create(set1), create(set2), create(set3)); } private void validateEqualsAndHashCode(PropertyValue p1, PropertyValue p2, PropertyValue p3) { @@ -892,7 +959,7 @@ public void testCompareTo() throws Exception { validateCompareTo(create(10D), create(10D), create(12D)); validateCompareTo(create(-10D), create(BigDecimal.valueOf(-10)), create(BigDecimal.valueOf(12))); validateCompareTo(create(10D), create(BigDecimal.valueOf(10)), create(BigDecimal.valueOf(12))); - //string + // string validateCompareTo(create("10"), create("10"), create("12")); // BigDecimal validateCompareTo(create(BigDecimal.valueOf(-10)), create((short)-10), create((short)12)); @@ -948,12 +1015,17 @@ public void testCompareToWithList() { create(LIST_VAL_a).compareTo(create(LIST_VAL_a)); } + @Test(expected = UnsupportedOperationException.class) + public void testCompareToWithSet() { + create(SET_VAL_f).compareTo(create(SET_VAL_f)); + } + @Test public void testArrayValueMaxSize() { PropertyValue property = new PropertyValue(); property.setBytes(new byte[PropertyValue.LARGE_PROPERTY_THRESHOLD]); } - + @Test public void testLargeArrayValue() { PropertyValue property = new PropertyValue(); @@ -964,12 +1036,12 @@ public void testLargeArrayValue() { public void testStringValueMaxSize() { create(new String(new byte[PropertyValue.LARGE_PROPERTY_THRESHOLD])); } - + @Test public void testLargeString() { create(new String(new byte[PropertyValue.LARGE_PROPERTY_THRESHOLD + 10])); } - + @Test public void testListValueMaxSize() { int n = PropertyValue.LARGE_PROPERTY_THRESHOLD / 9; @@ -979,7 +1051,7 @@ public void testListValueMaxSize() { } create(list); } - + @Test public void testLargeListValue() { // 8 bytes per double + 1 byte overhead @@ -990,7 +1062,7 @@ public void testLargeListValue() { } create(list); } - + @Test public void testMapValueMaxSize() { Map m = new HashMap<>(); @@ -1001,7 +1073,7 @@ public void testMapValueMaxSize() { } create(m); } - + @Test public void testLargeMapValue() { Map m = new HashMap<>(); @@ -1012,7 +1084,29 @@ public void testLargeMapValue() { } create(m); } - + + @Test + public void testSetValueMaxSize() { + Set s = new HashSet<>(); + // 8 bytes per double + 1 byte overhead + for (int i = 0; i < PropertyValue.LARGE_PROPERTY_THRESHOLD / 9; i++) { + PropertyValue p = create(Math.random()); + s.add(p); + } + create(s); + } + + @Test + public void testLargeSetValue() { + Set s = new HashSet<>(); + // 8 bytes per double + 1 byte overhead + for (int i = 0; i < PropertyValue.LARGE_PROPERTY_THRESHOLD / 9 + 1; i++) { + PropertyValue p = create(Math.random()); + s.add(p); + } + create(s); + } + @Test public void testBigDecimalValueMaxSize() { // internal representation of BigInteger needs 5 bytes @@ -1020,14 +1114,14 @@ public void testBigDecimalValueMaxSize() { Arrays.fill(bigendian, (byte) 121); create(new BigDecimal(new BigInteger(bigendian))); } - + @Test public void testLargeBigDecimal() { byte [] bigendian = new byte[Short.MAX_VALUE + 10]; Arrays.fill(bigendian, (byte) 121); create(new BigDecimal(new BigInteger(bigendian))); } - + @Test public void testWriteAndReadFields() throws IOException { PropertyValue p = create(NULL_VAL_0); @@ -1074,6 +1168,9 @@ public void testWriteAndReadFields() throws IOException { p = create(DATETIME_VAL_d); assertEquals(p, writeAndReadFields(PropertyValue.class, p)); + + p = create(SET_VAL_f); + assertEquals(p, writeAndReadFields(PropertyValue.class, p)); } @Test @@ -1122,6 +1219,9 @@ public void testGetType() { p = create(DATETIME_VAL_d); assertEquals(LocalDateTime.class, p.getType()); + + p = create(SET_VAL_f); + assertEquals(Set.class, p.getType()); } /** diff --git a/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueUtilsTest.java b/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueUtilsTest.java index e603ab8f084d..28fd82ce7da5 100644 --- a/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueUtilsTest.java +++ b/gradoop-common/src/test/java/org/gradoop/common/model/impl/properties/PropertyValueUtilsTest.java @@ -16,934 +16,1034 @@ package org.gradoop.common.model.impl.properties; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collection; import static org.gradoop.common.GradoopTestUtils.*; import static org.gradoop.common.model.impl.properties.PropertyValueUtils.Boolean.or; import static org.gradoop.common.model.impl.properties.PropertyValueUtils.Numeric.*; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.gradoop.common.model.impl.properties.PropertyValue.create; +/** + * Test class of {@link PropertyValueUtils} + */ +@RunWith(Enclosed.class) public class PropertyValueUtilsTest { - @Test - public void testOr() throws Exception { - PropertyValue p; - - p = or(create(true), create(true)); - assertTrue(p.isBoolean()); - assertTrue(p.getBoolean()); - - p = or(create(true), create(false)); - assertTrue(p.isBoolean()); - assertTrue(p.getBoolean()); - - p = or(create(false), create(true)); - assertTrue(p.isBoolean()); - assertTrue(p.getBoolean()); - - p = or(create(false), create(false)); - assertTrue(p.isBoolean()); - assertFalse(p.getBoolean()); - } - - @Test - public void testAddReturningBigDecimal() throws Exception { - PropertyValue p; - - // BigDecimal - p = add(create(BIG_DECIMAL_VAL_7), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // double - p = add(create(BIG_DECIMAL_VAL_7), create(DOUBLE_VAL_5)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(DOUBLE_VAL_5)).compareTo(p.getBigDecimal()), 0); - p = add(create(DOUBLE_VAL_5), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(DOUBLE_VAL_5)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // float - p = add(create(BIG_DECIMAL_VAL_7), create(FLOAT_VAL_4)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(FLOAT_VAL_4)).compareTo(p.getBigDecimal()), 0); - p = add(create(FLOAT_VAL_4), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(FLOAT_VAL_4)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // long - p = add(create(BIG_DECIMAL_VAL_7), create(LONG_VAL_3)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(LONG_VAL_3)).compareTo(p.getBigDecimal()), 0); - p = add(create(LONG_VAL_3), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(LONG_VAL_3)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // int - p = add(create(BIG_DECIMAL_VAL_7), create(INT_VAL_2)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(INT_VAL_2)).compareTo(p.getBigDecimal()), 0); - p = add(create(INT_VAL_2), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(INT_VAL_2)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // short - p = add(create(BIG_DECIMAL_VAL_7), create(SHORT_VAL_e)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(SHORT_VAL_e)).compareTo(p.getBigDecimal()), 0); - p = add(create(SHORT_VAL_e), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(SHORT_VAL_e)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - } - - @Test - public void testAddReturningDouble() { - PropertyValue p; - - // double - p = add(create(DOUBLE_VAL_5), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 + DOUBLE_VAL_5, p.getDouble(), 0); - - // float - p = add(create(DOUBLE_VAL_5), create(FLOAT_VAL_4)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 + FLOAT_VAL_4, p.getDouble(), 0); - p = add(create(FLOAT_VAL_4), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(FLOAT_VAL_4 + DOUBLE_VAL_5, p.getDouble(), 0); - - // long - p = add(create(DOUBLE_VAL_5), create(LONG_VAL_3)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 + LONG_VAL_3, p.getDouble(), 0); - p = add(create(LONG_VAL_3), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(LONG_VAL_3 + DOUBLE_VAL_5, p.getDouble(), 0); - - // int - p = add(create(DOUBLE_VAL_5), create(INT_VAL_2)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 + INT_VAL_2, p.getDouble(), 0); - p = add(create(INT_VAL_2), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(INT_VAL_2 + DOUBLE_VAL_5, p.getDouble(), 0); - - // short - p = add(create(DOUBLE_VAL_5), create(SHORT_VAL_e)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 + SHORT_VAL_e, p.getDouble(), 0); - p = add(create(SHORT_VAL_e), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(SHORT_VAL_e + DOUBLE_VAL_5, p.getDouble(), 0); - } - - @Test - public void testAddReturningFloat() { - PropertyValue p; - - // float - p = add(create(FLOAT_VAL_4), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 + FLOAT_VAL_4, p.getFloat(), 0); - - // long - p = add(create(FLOAT_VAL_4), create(LONG_VAL_3)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 + LONG_VAL_3, p.getFloat(), 0); - p = add(create(LONG_VAL_3), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(LONG_VAL_3 + FLOAT_VAL_4, p.getFloat(), 0); - - // int - p = add(create(FLOAT_VAL_4), create(INT_VAL_2)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 + INT_VAL_2, p.getFloat(), 0); - p = add(create(INT_VAL_2), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(INT_VAL_2 + FLOAT_VAL_4, p.getFloat(), 0); - - // short - p = add(create(FLOAT_VAL_4), create(SHORT_VAL_e)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 + SHORT_VAL_e, p.getFloat(), 0); - p = add(create(SHORT_VAL_e), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(SHORT_VAL_e + FLOAT_VAL_4, p.getFloat(), 0); - } - - @Test - public void testAddReturningLong() { - PropertyValue p; - - // long - p = add(create(LONG_VAL_3), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 + LONG_VAL_3, p.getLong(), 0); - - // int - p = add(create(LONG_VAL_3), create(INT_VAL_2)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 + INT_VAL_2, p.getLong(), 0); - p = add(create(INT_VAL_2), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(INT_VAL_2 + LONG_VAL_3, p.getLong(), 0); - - // short - p = add(create(LONG_VAL_3), create(SHORT_VAL_e)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 + SHORT_VAL_e, p.getLong(), 0); - p = add(create(SHORT_VAL_e), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(SHORT_VAL_e + LONG_VAL_3, p.getLong(), 0); - } - - @Test - public void testAddReturningInteger() { - PropertyValue p; - - // int - p = add(create(INT_VAL_2), create(INT_VAL_2)); - assertTrue(p.isInt()); - assertEquals(INT_VAL_2 + INT_VAL_2, p.getInt(), 0); - - // short - p = add(create(INT_VAL_2), create(SHORT_VAL_e)); - assertTrue(p.isInt()); - assertEquals(INT_VAL_2 + SHORT_VAL_e, p.getInt(), 0); - p = add(create(SHORT_VAL_e), create(INT_VAL_2)); - assertTrue(p.isInt()); - assertEquals(SHORT_VAL_e + INT_VAL_2, p.getInt(), 0); - p = add(create(SHORT_VAL_e), create(SHORT_VAL_e)); - assertTrue(p.isInt()); - assertEquals(SHORT_VAL_e + SHORT_VAL_e, p.getInt(), 0); - } - - @Test - public void testMultiplyReturningBigDecimal() throws Exception { - PropertyValue p; - - // BigDecimal - p = multiply(create(BIG_DECIMAL_VAL_7), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // double - p = multiply(create(BIG_DECIMAL_VAL_7), create(DOUBLE_VAL_5)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(DOUBLE_VAL_5)).compareTo(p.getBigDecimal()), 0); - p = multiply(create(DOUBLE_VAL_5), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(DOUBLE_VAL_5)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // float - p = multiply(create(BIG_DECIMAL_VAL_7), create(FLOAT_VAL_4)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(FLOAT_VAL_4)).compareTo(p.getBigDecimal()), 0); - p = multiply(create(FLOAT_VAL_4), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(FLOAT_VAL_4)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // long - p = multiply(create(BIG_DECIMAL_VAL_7), create(LONG_VAL_3)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(LONG_VAL_3)).compareTo(p.getBigDecimal()), 0); - p = multiply(create(LONG_VAL_3), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(LONG_VAL_3)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // int - p = multiply(create(BIG_DECIMAL_VAL_7), create(INT_VAL_2)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(INT_VAL_2)).compareTo(p.getBigDecimal()), 0); - p = multiply(create(INT_VAL_2), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(INT_VAL_2)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - - // short - p = multiply(create(BIG_DECIMAL_VAL_7), create(SHORT_VAL_e)); - assertTrue(p.isBigDecimal()); - assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(SHORT_VAL_e)).compareTo(p.getBigDecimal()), 0); - p = multiply(create(SHORT_VAL_e), create(BIG_DECIMAL_VAL_7)); - assertTrue(p.isBigDecimal()); - assertEquals((BigDecimal.valueOf(SHORT_VAL_e)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); - } - - @Test - public void testMultiplyReturningDouble() { - PropertyValue p; - - // double - p = multiply(create(DOUBLE_VAL_5), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 * DOUBLE_VAL_5, p.getDouble(), 0); - - // float - p = multiply(create(DOUBLE_VAL_5), create(FLOAT_VAL_4)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 * FLOAT_VAL_4, p.getDouble(), 0); - p = multiply(create(FLOAT_VAL_4), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(FLOAT_VAL_4 * DOUBLE_VAL_5, p.getDouble(), 0); - - // long - p = multiply(create(DOUBLE_VAL_5), create(LONG_VAL_3)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 * LONG_VAL_3, p.getDouble(), 0); - p = multiply(create(LONG_VAL_3), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(LONG_VAL_3 * DOUBLE_VAL_5, p.getDouble(), 0); - - // int - p = multiply(create(DOUBLE_VAL_5), create(INT_VAL_2)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 * INT_VAL_2, p.getDouble(), 0); - p = multiply(create(INT_VAL_2), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(INT_VAL_2 * DOUBLE_VAL_5, p.getDouble(), 0); - - // short - p = multiply(create(DOUBLE_VAL_5), create(SHORT_VAL_e)); - assertTrue(p.isDouble()); - assertEquals(DOUBLE_VAL_5 * SHORT_VAL_e, p.getDouble(), 0); - p = multiply(create(SHORT_VAL_e), create(DOUBLE_VAL_5)); - assertTrue(p.isDouble()); - assertEquals(SHORT_VAL_e * DOUBLE_VAL_5, p.getDouble(), 0); - } - - @Test - public void testMultiplyReturningFloat() { - PropertyValue p; - - // float - p = multiply(create(FLOAT_VAL_4), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 * FLOAT_VAL_4, p.getFloat(), 0); - - // long - p = multiply(create(FLOAT_VAL_4), create(LONG_VAL_3)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 * LONG_VAL_3, p.getFloat(), 0); - p = multiply(create(LONG_VAL_3), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(LONG_VAL_3 * FLOAT_VAL_4, p.getFloat(), 0); - - // int - p = multiply(create(FLOAT_VAL_4), create(INT_VAL_2)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 * INT_VAL_2, p.getFloat(), 0); - p = multiply(create(INT_VAL_2), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(INT_VAL_2 * FLOAT_VAL_4, p.getFloat(), 0); - - // short - p = multiply(create(FLOAT_VAL_4), create(SHORT_VAL_e)); - assertTrue(p.isFloat()); - assertEquals(FLOAT_VAL_4 * SHORT_VAL_e, p.getFloat(), 0); - p = multiply(create(SHORT_VAL_e), create(FLOAT_VAL_4)); - assertTrue(p.isFloat()); - assertEquals(SHORT_VAL_e * FLOAT_VAL_4, p.getFloat(), 0); - } - - @Test - public void testMultiplyReturningLong() { - PropertyValue p; - - // long - p = multiply(create(LONG_VAL_3), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 * LONG_VAL_3, p.getLong(), 0); - - // int - p = multiply(create(LONG_VAL_3), create(INT_VAL_2)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 * INT_VAL_2, p.getLong(), 0); - p = multiply(create(INT_VAL_2), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(INT_VAL_2 * LONG_VAL_3, p.getLong(), 0); - - // short - p = multiply(create(LONG_VAL_3), create(SHORT_VAL_e)); - assertTrue(p.isLong()); - assertEquals(LONG_VAL_3 * SHORT_VAL_e, p.getLong(), 0); - p = multiply(create(SHORT_VAL_e), create(LONG_VAL_3)); - assertTrue(p.isLong()); - assertEquals(SHORT_VAL_e * LONG_VAL_3, p.getLong(), 0); - } - - @Test - public void testMultiplyReturningInteger() { - PropertyValue p; - - // int - p = multiply(create(INT_VAL_2), create(INT_VAL_2)); - assertTrue(p.isInt()); - assertEquals(INT_VAL_2 * INT_VAL_2, p.getInt(), 0); - - // short - p = multiply(create(INT_VAL_2), create(SHORT_VAL_e)); - assertTrue(p.isInt()); - assertEquals(INT_VAL_2 * SHORT_VAL_e, p.getInt(), 0); - p = multiply(create(SHORT_VAL_e), create(INT_VAL_2)); - assertTrue(p.isInt()); - assertEquals(SHORT_VAL_e * INT_VAL_2, p.getInt(), 0); - p = multiply(create(SHORT_VAL_e), create(SHORT_VAL_e)); - assertTrue(p.isInt()); - assertEquals(SHORT_VAL_e * SHORT_VAL_e, p.getInt(), 0); + /** + * Test class of {@link PropertyValueUtils.Boolean} + */ + public static class BooleanTest { + @Test + public void testOr() { + PropertyValue p; + + p = or(create(true), create(true)); + assertTrue(p.isBoolean()); + assertTrue(p.getBoolean()); + + p = or(create(true), create(false)); + assertTrue(p.isBoolean()); + assertTrue(p.getBoolean()); + + p = or(create(false), create(true)); + assertTrue(p.isBoolean()); + assertTrue(p.getBoolean()); + + p = or(create(false), create(false)); + assertTrue(p.isBoolean()); + assertFalse(p.getBoolean()); + } } - @Test - public void testMin() throws Exception { - PropertyValue p; - BigDecimal minBigDecimal = new BigDecimal("10"); - BigDecimal maxBigDecimal = new BigDecimal("11"); - double minDouble = 10d; - double maxDouble = 11d; - float minFloat = 10f; - float maxFloat = 11f; - long minLong = 10L; - long maxLong = 11L; - int minInt = 10; - int maxInt = 11; - short minShort = (short)10; - short maxShort = (short)11; - - // MIN BigDecimal - p = min(create(minBigDecimal), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxBigDecimal), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - p = min(create(minBigDecimal), create(maxDouble)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxDouble), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - p = min(create(minBigDecimal), create(maxFloat)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxFloat), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - p = min(create(minBigDecimal), create(maxLong)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxLong), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - p = min(create(minBigDecimal), create(maxInt)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxInt), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - p = min(create(minBigDecimal), create(maxShort)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - p = min(create(maxShort), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); - - // MIN Double - p = min(create(minDouble), create(maxBigDecimal)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxBigDecimal), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - p = min(create(minDouble), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxDouble), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - p = min(create(minDouble), create(maxFloat)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxFloat), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - p = min(create(minDouble), create(maxLong)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxLong), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - p = min(create(minDouble), create(maxInt)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxInt), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - p = min(create(minDouble), create(maxShort)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - p = min(create(maxShort), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), minDouble, 0); - - // MIN Float - p = min(create(minFloat), create(maxBigDecimal)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxBigDecimal), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - p = min(create(minFloat), create(maxDouble)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxDouble), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - p = min(create(minFloat), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxFloat), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - p = min(create(minFloat), create(maxLong)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxLong), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - p = min(create(minFloat), create(maxInt)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxInt), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - p = min(create(minFloat), create(maxShort)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - p = min(create(maxShort), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), minFloat, 0); - - // MIN Long - p = min(create(minLong), create(maxBigDecimal)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxBigDecimal), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - p = min(create(minLong), create(maxDouble)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxDouble), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - p = min(create(minLong), create(maxFloat)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxFloat), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - p = min(create(minLong), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxLong), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - p = min(create(minLong), create(maxInt)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxInt), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - p = min(create(minLong), create(maxShort)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - p = min(create(maxShort), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), minLong, 0); - - // MIN Int - p = min(create(minInt), create(maxBigDecimal)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxBigDecimal), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - p = min(create(minInt), create(maxDouble)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxDouble), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - p = min(create(minInt), create(maxFloat)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxFloat), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - p = min(create(minInt), create(maxLong)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxLong), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - p = min(create(minInt), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxInt), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - p = min(create(minInt), create(maxShort)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - p = min(create(maxShort), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), minInt, 0); - - // MIN Short - p = min(create(minShort), create(maxBigDecimal)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxBigDecimal), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - - p = min(create(minShort), create(maxDouble)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxDouble), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - - p = min(create(minShort), create(maxFloat)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxFloat), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - - p = min(create(minShort), create(maxLong)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxLong), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - - p = min(create(minShort), create(maxInt)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxInt), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - - p = min(create(minShort), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); - p = min(create(maxShort), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), minShort, 0); + /** + * Test class of {@link PropertyValueUtils.Numeric} + */ + public static class NumericTest { + @Test + public void testAddReturningBigDecimal() throws Exception { + PropertyValue p; + + // BigDecimal + p = add(create(BIG_DECIMAL_VAL_7), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // double + p = add(create(BIG_DECIMAL_VAL_7), create(DOUBLE_VAL_5)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(DOUBLE_VAL_5)).compareTo(p.getBigDecimal()), 0); + p = add(create(DOUBLE_VAL_5), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(DOUBLE_VAL_5)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // float + p = add(create(BIG_DECIMAL_VAL_7), create(FLOAT_VAL_4)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(FLOAT_VAL_4)).compareTo(p.getBigDecimal()), 0); + p = add(create(FLOAT_VAL_4), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(FLOAT_VAL_4)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // long + p = add(create(BIG_DECIMAL_VAL_7), create(LONG_VAL_3)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(LONG_VAL_3)).compareTo(p.getBigDecimal()), 0); + p = add(create(LONG_VAL_3), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(LONG_VAL_3)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // int + p = add(create(BIG_DECIMAL_VAL_7), create(INT_VAL_2)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(INT_VAL_2)).compareTo(p.getBigDecimal()), 0); + p = add(create(INT_VAL_2), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(INT_VAL_2)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // short + p = add(create(BIG_DECIMAL_VAL_7), create(SHORT_VAL_e)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.add(BigDecimal.valueOf(SHORT_VAL_e)).compareTo(p.getBigDecimal()), 0); + p = add(create(SHORT_VAL_e), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(SHORT_VAL_e)).add(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + } + + @Test + public void testAddReturningDouble() { + PropertyValue p; + + // double + p = add(create(DOUBLE_VAL_5), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 + DOUBLE_VAL_5, p.getDouble(), 0); + + // float + p = add(create(DOUBLE_VAL_5), create(FLOAT_VAL_4)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 + FLOAT_VAL_4, p.getDouble(), 0); + p = add(create(FLOAT_VAL_4), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(FLOAT_VAL_4 + DOUBLE_VAL_5, p.getDouble(), 0); + + // long + p = add(create(DOUBLE_VAL_5), create(LONG_VAL_3)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 + LONG_VAL_3, p.getDouble(), 0); + p = add(create(LONG_VAL_3), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(LONG_VAL_3 + DOUBLE_VAL_5, p.getDouble(), 0); + + // int + p = add(create(DOUBLE_VAL_5), create(INT_VAL_2)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 + INT_VAL_2, p.getDouble(), 0); + p = add(create(INT_VAL_2), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(INT_VAL_2 + DOUBLE_VAL_5, p.getDouble(), 0); + + // short + p = add(create(DOUBLE_VAL_5), create(SHORT_VAL_e)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 + SHORT_VAL_e, p.getDouble(), 0); + p = add(create(SHORT_VAL_e), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(SHORT_VAL_e + DOUBLE_VAL_5, p.getDouble(), 0); + } + + @Test + public void testAddReturningFloat() { + PropertyValue p; + + // float + p = add(create(FLOAT_VAL_4), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 + FLOAT_VAL_4, p.getFloat(), 0); + + // long + p = add(create(FLOAT_VAL_4), create(LONG_VAL_3)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 + LONG_VAL_3, p.getFloat(), 0); + p = add(create(LONG_VAL_3), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(LONG_VAL_3 + FLOAT_VAL_4, p.getFloat(), 0); + + // int + p = add(create(FLOAT_VAL_4), create(INT_VAL_2)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 + INT_VAL_2, p.getFloat(), 0); + p = add(create(INT_VAL_2), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(INT_VAL_2 + FLOAT_VAL_4, p.getFloat(), 0); + + // short + p = add(create(FLOAT_VAL_4), create(SHORT_VAL_e)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 + SHORT_VAL_e, p.getFloat(), 0); + p = add(create(SHORT_VAL_e), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(SHORT_VAL_e + FLOAT_VAL_4, p.getFloat(), 0); + } + + @Test + public void testAddReturningLong() { + PropertyValue p; + + // long + p = add(create(LONG_VAL_3), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 + LONG_VAL_3, p.getLong(), 0); + + // int + p = add(create(LONG_VAL_3), create(INT_VAL_2)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 + INT_VAL_2, p.getLong(), 0); + p = add(create(INT_VAL_2), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(INT_VAL_2 + LONG_VAL_3, p.getLong(), 0); + + // short + p = add(create(LONG_VAL_3), create(SHORT_VAL_e)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 + SHORT_VAL_e, p.getLong(), 0); + p = add(create(SHORT_VAL_e), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(SHORT_VAL_e + LONG_VAL_3, p.getLong(), 0); + } + + @Test + public void testAddReturningInteger() { + PropertyValue p; + + // int + p = add(create(INT_VAL_2), create(INT_VAL_2)); + assertTrue(p.isInt()); + assertEquals(INT_VAL_2 + INT_VAL_2, p.getInt(), 0); + + // short + p = add(create(INT_VAL_2), create(SHORT_VAL_e)); + assertTrue(p.isInt()); + assertEquals(INT_VAL_2 + SHORT_VAL_e, p.getInt(), 0); + p = add(create(SHORT_VAL_e), create(INT_VAL_2)); + assertTrue(p.isInt()); + assertEquals(SHORT_VAL_e + INT_VAL_2, p.getInt(), 0); + p = add(create(SHORT_VAL_e), create(SHORT_VAL_e)); + assertTrue(p.isInt()); + assertEquals(SHORT_VAL_e + SHORT_VAL_e, p.getInt(), 0); + } + + @Test + public void testMultiplyReturningBigDecimal() throws Exception { + PropertyValue p; + + // BigDecimal + p = multiply(create(BIG_DECIMAL_VAL_7), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // double + p = multiply(create(BIG_DECIMAL_VAL_7), create(DOUBLE_VAL_5)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(DOUBLE_VAL_5)).compareTo(p.getBigDecimal()), 0); + p = multiply(create(DOUBLE_VAL_5), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(DOUBLE_VAL_5)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // float + p = multiply(create(BIG_DECIMAL_VAL_7), create(FLOAT_VAL_4)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(FLOAT_VAL_4)).compareTo(p.getBigDecimal()), 0); + p = multiply(create(FLOAT_VAL_4), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(FLOAT_VAL_4)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // long + p = multiply(create(BIG_DECIMAL_VAL_7), create(LONG_VAL_3)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(LONG_VAL_3)).compareTo(p.getBigDecimal()), 0); + p = multiply(create(LONG_VAL_3), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(LONG_VAL_3)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // int + p = multiply(create(BIG_DECIMAL_VAL_7), create(INT_VAL_2)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(INT_VAL_2)).compareTo(p.getBigDecimal()), 0); + p = multiply(create(INT_VAL_2), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(INT_VAL_2)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + + // short + p = multiply(create(BIG_DECIMAL_VAL_7), create(SHORT_VAL_e)); + assertTrue(p.isBigDecimal()); + assertEquals(BIG_DECIMAL_VAL_7.multiply(BigDecimal.valueOf(SHORT_VAL_e)).compareTo(p.getBigDecimal()), 0); + p = multiply(create(SHORT_VAL_e), create(BIG_DECIMAL_VAL_7)); + assertTrue(p.isBigDecimal()); + assertEquals((BigDecimal.valueOf(SHORT_VAL_e)).multiply(BIG_DECIMAL_VAL_7).compareTo(p.getBigDecimal()), 0); + } + + @Test + public void testMultiplyReturningDouble() { + PropertyValue p; + + // double + p = multiply(create(DOUBLE_VAL_5), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 * DOUBLE_VAL_5, p.getDouble(), 0); + + // float + p = multiply(create(DOUBLE_VAL_5), create(FLOAT_VAL_4)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 * FLOAT_VAL_4, p.getDouble(), 0); + p = multiply(create(FLOAT_VAL_4), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(FLOAT_VAL_4 * DOUBLE_VAL_5, p.getDouble(), 0); + + // long + p = multiply(create(DOUBLE_VAL_5), create(LONG_VAL_3)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 * LONG_VAL_3, p.getDouble(), 0); + p = multiply(create(LONG_VAL_3), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(LONG_VAL_3 * DOUBLE_VAL_5, p.getDouble(), 0); + + // int + p = multiply(create(DOUBLE_VAL_5), create(INT_VAL_2)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 * INT_VAL_2, p.getDouble(), 0); + p = multiply(create(INT_VAL_2), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(INT_VAL_2 * DOUBLE_VAL_5, p.getDouble(), 0); + + // short + p = multiply(create(DOUBLE_VAL_5), create(SHORT_VAL_e)); + assertTrue(p.isDouble()); + assertEquals(DOUBLE_VAL_5 * SHORT_VAL_e, p.getDouble(), 0); + p = multiply(create(SHORT_VAL_e), create(DOUBLE_VAL_5)); + assertTrue(p.isDouble()); + assertEquals(SHORT_VAL_e * DOUBLE_VAL_5, p.getDouble(), 0); + } + + @Test + public void testMultiplyReturningFloat() { + PropertyValue p; + + // float + p = multiply(create(FLOAT_VAL_4), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 * FLOAT_VAL_4, p.getFloat(), 0); + + // long + p = multiply(create(FLOAT_VAL_4), create(LONG_VAL_3)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 * LONG_VAL_3, p.getFloat(), 0); + p = multiply(create(LONG_VAL_3), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(LONG_VAL_3 * FLOAT_VAL_4, p.getFloat(), 0); + + // int + p = multiply(create(FLOAT_VAL_4), create(INT_VAL_2)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 * INT_VAL_2, p.getFloat(), 0); + p = multiply(create(INT_VAL_2), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(INT_VAL_2 * FLOAT_VAL_4, p.getFloat(), 0); + + // short + p = multiply(create(FLOAT_VAL_4), create(SHORT_VAL_e)); + assertTrue(p.isFloat()); + assertEquals(FLOAT_VAL_4 * SHORT_VAL_e, p.getFloat(), 0); + p = multiply(create(SHORT_VAL_e), create(FLOAT_VAL_4)); + assertTrue(p.isFloat()); + assertEquals(SHORT_VAL_e * FLOAT_VAL_4, p.getFloat(), 0); + } + + @Test + public void testMultiplyReturningLong() { + PropertyValue p; + + // long + p = multiply(create(LONG_VAL_3), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 * LONG_VAL_3, p.getLong(), 0); + + // int + p = multiply(create(LONG_VAL_3), create(INT_VAL_2)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 * INT_VAL_2, p.getLong(), 0); + p = multiply(create(INT_VAL_2), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(INT_VAL_2 * LONG_VAL_3, p.getLong(), 0); + + // short + p = multiply(create(LONG_VAL_3), create(SHORT_VAL_e)); + assertTrue(p.isLong()); + assertEquals(LONG_VAL_3 * SHORT_VAL_e, p.getLong(), 0); + p = multiply(create(SHORT_VAL_e), create(LONG_VAL_3)); + assertTrue(p.isLong()); + assertEquals(SHORT_VAL_e * LONG_VAL_3, p.getLong(), 0); + } + + @Test + public void testMultiplyReturningInteger() { + PropertyValue p; + + // int + p = multiply(create(INT_VAL_2), create(INT_VAL_2)); + assertTrue(p.isInt()); + assertEquals(INT_VAL_2 * INT_VAL_2, p.getInt(), 0); + + // short + p = multiply(create(INT_VAL_2), create(SHORT_VAL_e)); + assertTrue(p.isInt()); + assertEquals(INT_VAL_2 * SHORT_VAL_e, p.getInt(), 0); + p = multiply(create(SHORT_VAL_e), create(INT_VAL_2)); + assertTrue(p.isInt()); + assertEquals(SHORT_VAL_e * INT_VAL_2, p.getInt(), 0); + p = multiply(create(SHORT_VAL_e), create(SHORT_VAL_e)); + assertTrue(p.isInt()); + assertEquals(SHORT_VAL_e * SHORT_VAL_e, p.getInt(), 0); + } + + @Test + public void testMin() throws Exception { + PropertyValue p; + BigDecimal minBigDecimal = new BigDecimal("10"); + BigDecimal maxBigDecimal = new BigDecimal("11"); + double minDouble = 10d; + double maxDouble = 11d; + float minFloat = 10f; + float maxFloat = 11f; + long minLong = 10L; + long maxLong = 11L; + int minInt = 10; + int maxInt = 11; + short minShort = (short)10; + short maxShort = (short)11; + + // MIN BigDecimal + p = min(create(minBigDecimal), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxBigDecimal), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + p = min(create(minBigDecimal), create(maxDouble)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxDouble), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + p = min(create(minBigDecimal), create(maxFloat)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxFloat), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + p = min(create(minBigDecimal), create(maxLong)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxLong), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + p = min(create(minBigDecimal), create(maxInt)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxInt), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + p = min(create(minBigDecimal), create(maxShort)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + p = min(create(maxShort), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(minBigDecimal), 0); + + // MIN Double + p = min(create(minDouble), create(maxBigDecimal)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxBigDecimal), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + p = min(create(minDouble), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxDouble), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + p = min(create(minDouble), create(maxFloat)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxFloat), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + p = min(create(minDouble), create(maxLong)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxLong), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + p = min(create(minDouble), create(maxInt)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxInt), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + p = min(create(minDouble), create(maxShort)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + p = min(create(maxShort), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), minDouble, 0); + + // MIN Float + p = min(create(minFloat), create(maxBigDecimal)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxBigDecimal), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + p = min(create(minFloat), create(maxDouble)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxDouble), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + p = min(create(minFloat), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxFloat), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + p = min(create(minFloat), create(maxLong)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxLong), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + p = min(create(minFloat), create(maxInt)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxInt), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + p = min(create(minFloat), create(maxShort)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + p = min(create(maxShort), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), minFloat, 0); + + // MIN Long + p = min(create(minLong), create(maxBigDecimal)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxBigDecimal), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + p = min(create(minLong), create(maxDouble)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxDouble), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + p = min(create(minLong), create(maxFloat)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxFloat), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + p = min(create(minLong), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxLong), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + p = min(create(minLong), create(maxInt)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxInt), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + p = min(create(minLong), create(maxShort)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + p = min(create(maxShort), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), minLong, 0); + + // MIN Int + p = min(create(minInt), create(maxBigDecimal)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxBigDecimal), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + p = min(create(minInt), create(maxDouble)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxDouble), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + p = min(create(minInt), create(maxFloat)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxFloat), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + p = min(create(minInt), create(maxLong)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxLong), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + p = min(create(minInt), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxInt), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + p = min(create(minInt), create(maxShort)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + p = min(create(maxShort), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), minInt, 0); + + // MIN Short + p = min(create(minShort), create(maxBigDecimal)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxBigDecimal), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + + p = min(create(minShort), create(maxDouble)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxDouble), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + + p = min(create(minShort), create(maxFloat)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxFloat), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + + p = min(create(minShort), create(maxLong)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxLong), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + + p = min(create(minShort), create(maxInt)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxInt), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + + p = min(create(minShort), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + p = min(create(maxShort), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), minShort, 0); + } + + @Test + public void testMax() throws Exception { + PropertyValue p; + BigDecimal minBigDecimal = new BigDecimal("10"); + BigDecimal maxBigDecimal = new BigDecimal("11"); + double minDouble = 10d; + double maxDouble = 11d; + float minFloat = 10f; + float maxFloat = 11f; + long minLong = 10L; + long maxLong = 11L; + int minInt = 10; + int maxInt = 11; + short minShort = (short)10; + short maxShort = (short)11; + + // MAX BigDecimal + p = max(create(maxBigDecimal), create(minBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minBigDecimal), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + p = max(create(maxBigDecimal), create(minDouble)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minDouble), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + p = max(create(maxBigDecimal), create(minFloat)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minFloat), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + p = max(create(maxBigDecimal), create(minLong)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minLong), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + p = max(create(maxBigDecimal), create(minInt)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minInt), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + p = max(create(maxBigDecimal), create(minShort)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + p = max(create(minShort), create(maxBigDecimal)); + assertTrue(p.isBigDecimal()); + assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); + + // MAX Double + p = max(create(maxDouble), create(minBigDecimal)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minBigDecimal), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + p = max(create(maxDouble), create(minDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minDouble), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + p = max(create(maxDouble), create(minFloat)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minFloat), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + p = max(create(maxDouble), create(minLong)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minLong), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + p = max(create(maxDouble), create(minInt)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minInt), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + p = max(create(maxDouble), create(minShort)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + p = max(create(minShort), create(maxDouble)); + assertTrue(p.isDouble()); + assertEquals(p.getDouble(), maxDouble, 0); + + // MAX Float + p = max(create(maxFloat), create(minBigDecimal)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minBigDecimal), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + p = max(create(maxFloat), create(minDouble)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minDouble), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + p = max(create(maxFloat), create(minFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minFloat), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + p = max(create(maxFloat), create(minLong)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minLong), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + p = max(create(maxFloat), create(minInt)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minInt), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + p = max(create(maxFloat), create(minShort)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + p = max(create(minShort), create(maxFloat)); + assertTrue(p.isFloat()); + assertEquals(p.getFloat(), maxFloat, 0); + + // MAX Long + p = max(create(maxLong), create(minBigDecimal)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minBigDecimal), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + p = max(create(maxLong), create(minDouble)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minDouble), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + p = max(create(maxLong), create(minFloat)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minFloat), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + p = max(create(maxLong), create(minLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minLong), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + p = max(create(maxLong), create(minInt)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minInt), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + p = max(create(maxLong), create(minShort)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + p = max(create(minShort), create(maxLong)); + assertTrue(p.isLong()); + assertEquals(p.getLong(), maxLong, 0); + + // MAX Int + p = max(create(maxInt), create(minBigDecimal)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minBigDecimal), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + p = max(create(maxInt), create(minDouble)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minDouble), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + p = max(create(maxInt), create(minFloat)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minFloat), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + p = max(create(maxInt), create(minLong)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minLong), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + p = max(create(maxInt), create(minInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minInt), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + p = max(create(maxInt), create(minShort)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + p = max(create(minShort), create(maxInt)); + assertTrue(p.isInt()); + assertEquals(p.getInt(), maxInt, 0); + + // MAX Short + p = max(create(maxShort), create(minBigDecimal)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minBigDecimal), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + + p = max(create(maxShort), create(minDouble)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minDouble), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + + p = max(create(maxShort), create(minFloat)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minFloat), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + + p = max(create(maxShort), create(minLong)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minLong), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + + p = max(create(maxShort), create(minInt)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minInt), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + + p = max(create(maxShort), create(minShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + p = max(create(minShort), create(maxShort)); + assertTrue(p.isShort()); + assertEquals(p.getShort(), maxShort, 0); + } } - @Test - public void testMax() throws Exception { - PropertyValue p; - BigDecimal minBigDecimal = new BigDecimal("10"); - BigDecimal maxBigDecimal = new BigDecimal("11"); - double minDouble = 10d; - double maxDouble = 11d; - float minFloat = 10f; - float maxFloat = 11f; - long minLong = 10L; - long maxLong = 11L; - int minInt = 10; - int maxInt = 11; - short minShort = (short)10; - short maxShort = (short)11; - - // MAX BigDecimal - p = max(create(maxBigDecimal), create(minBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minBigDecimal), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - p = max(create(maxBigDecimal), create(minDouble)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minDouble), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - p = max(create(maxBigDecimal), create(minFloat)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minFloat), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - p = max(create(maxBigDecimal), create(minLong)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minLong), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - p = max(create(maxBigDecimal), create(minInt)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minInt), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - p = max(create(maxBigDecimal), create(minShort)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - p = max(create(minShort), create(maxBigDecimal)); - assertTrue(p.isBigDecimal()); - assertEquals(p.getBigDecimal().compareTo(maxBigDecimal), 0); - - // MAX Double - p = max(create(maxDouble), create(minBigDecimal)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minBigDecimal), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - p = max(create(maxDouble), create(minDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minDouble), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - p = max(create(maxDouble), create(minFloat)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minFloat), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - p = max(create(maxDouble), create(minLong)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minLong), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - p = max(create(maxDouble), create(minInt)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minInt), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - p = max(create(maxDouble), create(minShort)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - p = max(create(minShort), create(maxDouble)); - assertTrue(p.isDouble()); - assertEquals(p.getDouble(), maxDouble, 0); - - // MAX Float - p = max(create(maxFloat), create(minBigDecimal)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minBigDecimal), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - p = max(create(maxFloat), create(minDouble)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minDouble), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - p = max(create(maxFloat), create(minFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minFloat), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - p = max(create(maxFloat), create(minLong)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minLong), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - p = max(create(maxFloat), create(minInt)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minInt), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - p = max(create(maxFloat), create(minShort)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - p = max(create(minShort), create(maxFloat)); - assertTrue(p.isFloat()); - assertEquals(p.getFloat(), maxFloat, 0); - - // MAX Long - p = max(create(maxLong), create(minBigDecimal)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minBigDecimal), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - p = max(create(maxLong), create(minDouble)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minDouble), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - p = max(create(maxLong), create(minFloat)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minFloat), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - p = max(create(maxLong), create(minLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minLong), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - p = max(create(maxLong), create(minInt)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minInt), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - p = max(create(maxLong), create(minShort)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - p = max(create(minShort), create(maxLong)); - assertTrue(p.isLong()); - assertEquals(p.getLong(), maxLong, 0); - - // MAX Int - p = max(create(maxInt), create(minBigDecimal)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minBigDecimal), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - p = max(create(maxInt), create(minDouble)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minDouble), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - p = max(create(maxInt), create(minFloat)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minFloat), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - p = max(create(maxInt), create(minLong)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minLong), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - p = max(create(maxInt), create(minInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minInt), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - p = max(create(maxInt), create(minShort)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - p = max(create(minShort), create(maxInt)); - assertTrue(p.isInt()); - assertEquals(p.getInt(), maxInt, 0); - - // MAX Short - p = max(create(maxShort), create(minBigDecimal)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minBigDecimal), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - - p = max(create(maxShort), create(minDouble)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minDouble), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - - p = max(create(maxShort), create(minFloat)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minFloat), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - - p = max(create(maxShort), create(minLong)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minLong), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - - p = max(create(maxShort), create(minInt)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minInt), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - - p = max(create(maxShort), create(minShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); - p = max(create(minShort), create(maxShort)); - assertTrue(p.isShort()); - assertEquals(p.getShort(), maxShort, 0); + /** + * Test class for {@link PropertyValueUtils.Bytes} class + */ + @RunWith(Parameterized.class) + public static class BytesTest { + /** + * The property value to test + */ + private PropertyValue propertyValue; + + /** + * The property value type byte + */ + private byte type; + + /** + * Constructor to use with parameterized class + * + * @param propertyValue the property value to test + */ + public BytesTest(PropertyValue propertyValue, byte type) { + this.propertyValue = propertyValue; + this.type = type; + } + + /** + * Properties to use as parameters + * + * @return a collection of property values and their type bytes + */ + @Parameterized.Parameters + public static Collection properties() { + return Arrays.asList(new Object[][] { + {create(NULL_VAL_0), PropertyValue.TYPE_NULL}, + {create(BOOL_VAL_1), PropertyValue.TYPE_BOOLEAN}, + {create(INT_VAL_2), PropertyValue.TYPE_INTEGER}, + {create(LONG_VAL_3), PropertyValue.TYPE_LONG}, + {create(FLOAT_VAL_4), PropertyValue.TYPE_FLOAT}, + {create(DOUBLE_VAL_5), PropertyValue.TYPE_DOUBLE}, + {create(STRING_VAL_6), PropertyValue.TYPE_STRING}, + {create(BIG_DECIMAL_VAL_7), PropertyValue.TYPE_BIG_DECIMAL}, + {create(GRADOOP_ID_VAL_8), PropertyValue.TYPE_GRADOOP_ID}, + {create(MAP_VAL_9), PropertyValue.TYPE_MAP}, + {create(LIST_VAL_a), PropertyValue.TYPE_LIST}, + {create(DATE_VAL_b), PropertyValue.TYPE_DATE}, + {create(TIME_VAL_c), PropertyValue.TYPE_TIME}, + {create(DATETIME_VAL_d), PropertyValue.TYPE_DATETIME}, + {create(SHORT_VAL_e), PropertyValue.TYPE_SHORT} + }); + } + + /** + * Test static function {@link PropertyValueUtils.Bytes#getRawBytesWithoutType(PropertyValue)} + */ + @Test + public void testGetRawBytesWithoutType() { + assertArrayEquals(Arrays.copyOfRange(propertyValue.getRawBytes(), 1, propertyValue.getRawBytes().length), + PropertyValueUtils.Bytes.getRawBytesWithoutType(propertyValue)); + } + + /** + * Test static function {@link PropertyValueUtils.Bytes#getTypeByte(PropertyValue)} + */ + @Test + public void testGetTypeByte() { + assertArrayEquals(new byte[] {type}, PropertyValueUtils.Bytes.getTypeByte(propertyValue)); + } + + /** + * Test static function {@link PropertyValueUtils.Bytes#createFromTypeValueBytes(byte[], byte[])}} + */ + @Test + public void testCreateFromTypeValueBytes() { + assertEquals(propertyValue, PropertyValueUtils.Bytes + .createFromTypeValueBytes(new byte[] {type}, + Arrays.copyOfRange(propertyValue.getRawBytes(), + 1, propertyValue.getRawBytes().length))); + } } } diff --git a/gradoop-examples/pom.xml b/gradoop-examples/pom.xml index a5bf5a218757..5f6f273d5603 100644 --- a/gradoop-examples/pom.xml +++ b/gradoop-examples/pom.xml @@ -5,7 +5,7 @@ org.gradoop gradoop-parent - 0.5.0-SNAPSHOT + 0.4.1 gradoop-examples @@ -126,6 +126,10 @@ + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/CypherBenchmark.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/CypherBenchmark.java new file mode 100644 index 000000000000..e51fa58720b3 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/CypherBenchmark.java @@ -0,0 +1,245 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.benchmark.cypher; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.io.FileUtils; +import org.apache.flink.api.common.ProgramDescription; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.hadoop.conf.Configuration; +import org.gradoop.benchmark.subgraph.SubgraphBenchmark; +import org.gradoop.examples.AbstractRunner; +import org.gradoop.flink.io.api.DataSource; +import org.gradoop.flink.io.impl.csv.indexed.IndexedCSVDataSource; +import org.gradoop.flink.model.api.epgm.GraphCollection; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatistics; +import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatisticsHDFSReader; +import org.gradoop.flink.util.GradoopFlinkConfig; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +/** + * A dedicated program for parametrized graph cypher benchmark. + */ +public class CypherBenchmark extends AbstractRunner implements ProgramDescription { + /** + * Option to declare path to indexed input graph + */ + private static final String OPTION_INPUT_PATH = "i"; + /** + * Option do declare path to statistics + */ + private static final String OPTION_STATISTICS_PATH = "s"; + /** + * Option to declare output path to statistics csv file + */ + private static final String OPTION_CSV_PATH = "c"; + /** + * Option to declare verification + */ + private static final String OPTION_QUERY = "q"; + /** + * Option for used first name in query. + */ + private static final String OPTION_FIRST_NAME = "n"; + /** + * Used input path + */ + private static String INPUT_PATH; + /** + * Used to indicate if statistics are used + */ + private static boolean HAS_STATISTICS; + /** + * Used statistics input path + */ + private static String STATISTICS_INPUT_PATH; + /** + * Used output path for csv statistics + */ + private static String CSV_PATH; + /** + * Used query + */ + private static String QUERY; + /** + * Used first name for query (q1,q2,q3) + */ + private static String FIRST_NAME; + + static { + OPTIONS.addOption(OPTION_INPUT_PATH, "input", true, + "Input path to indexed source files."); + OPTIONS.addOption(OPTION_CSV_PATH, "csv", true, + "Output path to csv statistics output"); + OPTIONS.addOption(OPTION_QUERY, "query", true, + "Used query (q1,q2,q3,q4,q5,q6)"); + OPTIONS.addOption(OPTION_FIRST_NAME, "query-name", true, + "Used first Name in Cypher Query"); + OPTIONS.addOption(OPTION_STATISTICS_PATH, "statistics", true, + "Input path to previously generated statistics."); + } + + /** + * Main program to run the benchmark. Arguments are the available options. + * + * @param args program arguments + * @throws Exception IO or execution Exception + */ + public static void main(String[] args) throws Exception { + CommandLine cmd = parseArguments(args, SubgraphBenchmark.class.getName()); + + if (cmd == null) { + System.exit(1); + } + + // test if minimum arguments are set + performSanityCheck(cmd); + + // read cmd arguments + readCMDArguments(cmd); + + ExecutionEnvironment env = getExecutionEnvironment(); + GradoopFlinkConfig config = GradoopFlinkConfig.createConfig(env); + + // read graph + DataSource source = new IndexedCSVDataSource(INPUT_PATH, config); + LogicalGraph graph = source.getLogicalGraph(); + + // prepare collection + GraphCollection collection; + + // get cypher query + String query = getQuery(QUERY); + + // execute cypher with or without statistics + if (HAS_STATISTICS) { + GraphStatistics statistics = GraphStatisticsHDFSReader + .read(STATISTICS_INPUT_PATH, new Configuration()); + + collection = graph.query(query, statistics); + } else { + collection = graph.query(query); + } + + // count embeddings + System.out.println(collection.getGraphHeads().count()); + + // execute and write job statistics + writeCSV(env); + } + + /** + * Returns used query for benchmark + * + * @param query argument input + * @return used query + */ + private static String getQuery(String query) { + switch (query) { + case "q1" : return Queries.q1(FIRST_NAME); + case "q2" : return Queries.q2(FIRST_NAME); + case "q3" : return Queries.q3(FIRST_NAME); + case "q4" : return Queries.q4(); + case "q5" : return Queries.q5(); + case "q6" : return Queries.q6(); + default : throw new IllegalArgumentException("Unsupported query: " + query); + } + } + + /** + * Reads the given arguments from command line + * + * @param cmd command line + */ + private static void readCMDArguments(CommandLine cmd) { + INPUT_PATH = cmd.getOptionValue(OPTION_INPUT_PATH); + CSV_PATH = cmd.getOptionValue(OPTION_CSV_PATH); + QUERY = cmd.getOptionValue(OPTION_QUERY); + HAS_STATISTICS = cmd.hasOption(OPTION_STATISTICS_PATH); + STATISTICS_INPUT_PATH = cmd.getOptionValue(OPTION_STATISTICS_PATH); + FIRST_NAME = cmd.getOptionValue(OPTION_FIRST_NAME); + } + + /** + * Checks if the minimum of arguments is provided + * + * @param cmd command line + */ + private static void performSanityCheck(CommandLine cmd) { + if (!cmd.hasOption(OPTION_INPUT_PATH)) { + throw new IllegalArgumentException("Define a graph input directory."); + } + if (!cmd.hasOption(OPTION_CSV_PATH)) { + throw new IllegalArgumentException("Path to CSV-File need to be set."); + } + if (!cmd.hasOption(OPTION_QUERY)) { + throw new IllegalArgumentException("Define a query to run (q1,q2,q3,q4,q5,q6)."); + } + if (cmd.getOptionValue(OPTION_QUERY).equals("q1") || + cmd.getOptionValue(OPTION_QUERY).equals("q2") || + cmd.getOptionValue(OPTION_QUERY).equals("q3")) { + if (!cmd.hasOption(OPTION_FIRST_NAME)) { + throw new IllegalArgumentException("Define a first name for query"); + } + } + } + + /** + * Method to create and add lines to a csv-file + * + * @param env given ExecutionEnvironment + * @throws IOException exeption during file writing + */ + private static void writeCSV(ExecutionEnvironment env) throws IOException { + + String head = String.format("%s|%s|%s|%s|%s%n", + "Parallelism", + "dataset", + "query", + "usedStatistics", + "Runtime(s)"); + + String tail = String.format("%s|%s|%s|%s|%s%n", + env.getParallelism(), + INPUT_PATH, + QUERY, + HAS_STATISTICS, + env.getLastJobExecutionResult().getNetRuntime(TimeUnit.SECONDS)); + + File f = new File(CSV_PATH); + if (f.exists() && !f.isDirectory()) { + FileUtils.writeStringToFile(f, tail, true); + } else { + PrintWriter writer = new PrintWriter(CSV_PATH, "UTF-8"); + writer.print(head); + writer.print(tail); + writer.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescription() { + return CypherBenchmark.class.getName(); + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/Queries.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/Queries.java new file mode 100644 index 000000000000..79461fa92e60 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/Queries.java @@ -0,0 +1,104 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.benchmark.cypher; + +/** + * Used Queries for {@link CypherBenchmark} + */ +class Queries { + + /** + * Operational Query 1 + * + * @param name used first name in query + * @return query string + */ + static String q1(String name) { + return + "MATCH (p:person)<-[:hasCreator]-(c:comment), " + + "(p)<-[:hasCreator]-(po:post) " + + "WHERE p.firstName = '" + name + "'"; + } + + /** + * Operational Query 2 + * + * @param name used first name in query + * @return query string + */ + static String q2(String name) { + return + "MATCH (p:person)<-[:hasCreator]-(c:comment)," + + "(p)<-[:hasCreator]-(po:post)," + + "(c)-[:replyOf*0..10]->(po)" + + "WHERE p.firstName = '" + name + "'"; + } + + /** + * Operational Query 3 + * + * @param name used first name in query + * @return query string + */ + static String q3(String name) { + return + "MATCH (p1:person )-[:knows]->(p2:person)," + + "(c:comment)-[:hasCreator]->(p2)" + + "(c)-[:replyOf*0..10]->(po:post)" + + "(po)-[:hasCreator]->(p1)" + + "WHERE p1.firstName = '" + name + "'"; + + } + + /** + * Analytical Query 1 + * + * @return query string + */ + static String q4() { + return + "MATCH (p:person)-[:isLocatedIn]->(c:city)," + + "(p)-[:hasInterest]->(t:tag)," + + "(p)-[:studyAt]->(u:university)," + + "(p)<-[:hasMember]-(f:forum)," + + "(p)<-[:hasModerator]-(f)"; + } + + /** + * Analytical Query 2 + * + * @return query string + */ + static String q5() { + return + "MATCH (p1:person)-[:knows]->(p2:person)," + + "(p2)-[:knows]->(p3:person)," + + "(p1)-[:knows]->(p3)"; + } + + /** + * Analytical Query 3 + * + * @return query string + */ + static String q6() { + return + "MATCH (p1:person)-[:knows]->(p2:person)," + + "(p1)-[:hasInterest]->(t1:tag)," + + "(p2)-[:hasInterest]->(t1)," + + "(p2)-[:hasInterest]->(t2:tag)"; + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/package-info.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/package-info.java new file mode 100644 index 000000000000..aad5b5ebdc3f --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/cypher/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains benchmark classes (cypher) + */ +package org.gradoop.benchmark.cypher; diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/grouping/GroupingBenchmark.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/grouping/GroupingBenchmark.java index 66b47c648bfd..68933d22aa34 100644 --- a/gradoop-examples/src/main/java/org/gradoop/benchmark/grouping/GroupingBenchmark.java +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/grouping/GroupingBenchmark.java @@ -46,6 +46,10 @@ public class GroupingBenchmark extends AbstractRunner * Option to declare path to input graph */ private static final String OPTION_INPUT_PATH = "i"; + /** + * Option to declare input graph format (csv, indexed, json) + */ + private static final String OPTION_INPUT_FORMAT = "f"; /** * Option to declare path to output graph */ @@ -118,6 +122,10 @@ public class GroupingBenchmark extends AbstractRunner * Used hdfs INPUT_PATH */ private static String INPUT_PATH; + /** + * Used INPUT_FORMAT + */ + private static String INPUT_FORMAT; /** * Used hdfs OUTPUT_PATH */ @@ -163,6 +171,8 @@ public class GroupingBenchmark extends AbstractRunner static { OPTIONS.addOption(OPTION_INPUT_PATH, "vertex-input-path", true, "Path to vertex file"); + OPTIONS.addOption(OPTION_INPUT_FORMAT, "input-format", true, + "Format of the input [csv, indexed, json]. Default: " + DEFAULT_FORMAT); OPTIONS.addOption(OPTION_OUTPUT_PATH, "output-path", true, "Path to write output files to"); OPTIONS.addOption(OPTION_GROUPING_STRATEGY, "strategy", true, @@ -211,7 +221,7 @@ public static void main(String[] args) throws Exception { readCMDArguments(cmd); // initialize EPGM database - LogicalGraph graphDatabase = readLogicalGraph(INPUT_PATH); + LogicalGraph graphDatabase = readLogicalGraph(INPUT_PATH, INPUT_FORMAT); // initialize grouping keys List vertexKeys = Lists.newArrayList(); @@ -293,6 +303,10 @@ private static void readCMDArguments(final CommandLine cmd) { OUTPUT_PATH = cmd.getOptionValue(OPTION_OUTPUT_PATH); CSV_PATH = cmd.getOptionValue(OPTION_CSV_PATH); + // input format + INPUT_FORMAT = cmd.hasOption(OPTION_INPUT_FORMAT) ? + cmd.getOptionValue(OPTION_INPUT_FORMAT).toLowerCase() : DEFAULT_FORMAT; + // initialize grouping strategy if (cmd.hasOption(OPTION_GROUPING_STRATEGY)) { String value = cmd.getOptionValue(OPTION_GROUPING_STRATEGY); diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/patternmatching/Queries.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/patternmatching/Queries.java index bdcc0357b08b..3adb11285738 100644 --- a/gradoop-examples/src/main/java/org/gradoop/benchmark/patternmatching/Queries.java +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/patternmatching/Queries.java @@ -98,15 +98,6 @@ public static Query q1() { * * (0)<-0-(1)-1->(2) * - * static: - * TraversalCode{steps=[(1,0,0,true), (1,1,2,true)]} - * embeddingCount = 67.833.471 - * - * GDL: - * TraversalCode{steps=[(0,0,1,false), (1,1,2,true)]} - * embeddingCount = 62.728.432 - * - * * @return query q2 */ public static Query q2() { diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/SocialNetworkAnalyticsExample.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/SocialNetworkAnalyticsExample.java new file mode 100644 index 000000000000..15d39018917c --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/SocialNetworkAnalyticsExample.java @@ -0,0 +1,251 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.benchmark.sna; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.io.FileUtils; +import org.apache.flink.api.common.ProgramDescription; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.hadoop.conf.Configuration; +import org.gradoop.benchmark.sna.functions.CountFilter; +import org.gradoop.benchmark.subgraph.SubgraphBenchmark; +import org.gradoop.examples.AbstractRunner; +import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.api.DataSource; +import org.gradoop.flink.io.impl.csv.CSVDataSink; +import org.gradoop.flink.io.impl.csv.indexed.IndexedCSVDataSource; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.operators.combination.ReduceCombination; +import org.gradoop.flink.model.impl.operators.grouping.Grouping; +import org.gradoop.flink.model.impl.operators.grouping.GroupingStrategy; +import org.gradoop.flink.model.impl.operators.grouping.functions.aggregation.CountAggregator; +import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatistics; +import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatisticsHDFSReader; +import org.gradoop.flink.model.impl.operators.subgraph.functions.LabelIsIn; +import org.gradoop.flink.util.GradoopFlinkConfig; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +/** + * A dedicated program to evaluate a more complex social network analytics example. + */ +public class SocialNetworkAnalyticsExample extends AbstractRunner implements ProgramDescription { + /** + * Option to declare path to input graph + */ + private static final String OPTION_INPUT_PATH = "i"; + /** + * Option to declare path to output graph + */ + private static final String OPTION_OUTPUT_PATH = "o"; + /** + * Option to declare output path to statistics csv file + */ + private static final String OPTION_CSV_PATH = "c"; + /** + * Option to declare used statistics + */ + private static final String OPTION_STATISTICS_PATH = "s"; + /** + * Used input path + */ + private static String INPUT_PATH; + /** + * Used output path + */ + private static String OUTPUT_PATH; + /** + * Used csv path + */ + private static String CSV_PATH; + /** + * Used graph statistics (used for optimization) + */ + private static String STATISTICS_PATH; + + static { + OPTIONS.addOption(OPTION_INPUT_PATH, "input", true, + "Path to source files."); + OPTIONS.addOption(OPTION_OUTPUT_PATH, "output", true, + "Path to output file"); + OPTIONS.addOption(OPTION_CSV_PATH, "csv", true, + "Path to csv statistics"); + OPTIONS.addOption(OPTION_STATISTICS_PATH, "statistics", true, + "Path to graph statistics"); + } + + /** + * Main program to run the benchmark. Arguments are the available options. + * + * @param args program arguments + * @throws Exception IO or execution Exception + */ + public static void main(String[] args) throws Exception { + CommandLine cmd = parseArguments(args, SubgraphBenchmark.class.getName()); + + if (cmd == null) { + System.exit(1); + } + + // test if minimum arguments are set + performSanityCheck(cmd); + + // read cmd arguments + readCMDArguments(cmd); + + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + GradoopFlinkConfig conf = GradoopFlinkConfig.createConfig(env); + + // read logical graph + DataSource source = new IndexedCSVDataSource(INPUT_PATH, conf); + LogicalGraph graph = source.getLogicalGraph(); + + // create subgraph containing vertices with label: person, tag, country, city and post + // and its incident edges + graph = graph.vertexInducedSubgraph(new LabelIsIn<>( + "person", "tag", "country", "city", "post")); + + // call cypher function (with or without statistics) + if (cmd.hasOption(OPTION_STATISTICS_PATH)) { + GraphStatistics statistics = GraphStatisticsHDFSReader + .read(STATISTICS_PATH, new Configuration()); + + graph = graph + .query(getQuery(), getConstruction(), statistics) + .reduce(new ReduceCombination()); + + } else { + graph = graph + .query(getQuery(), getConstruction()) + .reduce(new ReduceCombination()); + } + + // group on vertex and edge labels + count grouped edges + LogicalGraph groupedGraph = new Grouping.GroupingBuilder() + .setStrategy(GroupingStrategy.GROUP_COMBINE) + .addVertexGroupingKey("name") + .useEdgeLabel(true).useVertexLabel(true) + .addEdgeAggregator(new CountAggregator()) + .build().execute(graph); + + // filter all edges below a fixed threshold + groupedGraph = groupedGraph.edgeInducedSubgraph(new CountFilter()); + + // write data to sink + DataSink sink = new CSVDataSink(OUTPUT_PATH, conf); + sink.write(groupedGraph); + + // execute and write job statistics + env.execute(); + writeCSV(env); + } + + /** + * Reads the given arguments from command line + * + * @param cmd command line + */ + private static void readCMDArguments(CommandLine cmd) { + INPUT_PATH = cmd.getOptionValue(OPTION_INPUT_PATH); + OUTPUT_PATH = cmd.getOptionValue(OPTION_OUTPUT_PATH); + CSV_PATH = cmd.getOptionValue(OPTION_CSV_PATH); + STATISTICS_PATH = cmd.getOptionValue(OPTION_STATISTICS_PATH); + } + + /** + * Returns used cypher query + * + * @return used cypher query + */ + private static String getQuery() { + return + "MATCH (p1:person)<-[:hasCreator]-(po:post)<-[:likes]-(p2:person)\n" + + "(p1)-[:isLocatedIn]->(c1:city)\n" + + "(p2)-[:isLocatedIn]->(c2:city)" + + "(po)-[:hasTag]->(t:tag)\n" + + "(c1)-[:isPartOf]->(ca:country)<-[:isPartOf]-(c2)\n" + + "WHERE p1 != p2"; + } + + /** + * Returns used construction pattern + * + * @return used construction pattern + */ + private static String getConstruction() { + return "CONSTRUCT (ca)-[new:hasInterest]->(t)"; + } + + /** + * Checks if the minimum of arguments is provided + * + * @param cmd command line + */ + private static void performSanityCheck(CommandLine cmd) { + if (!cmd.hasOption(OPTION_INPUT_PATH)) { + throw new IllegalArgumentException("Define a graph input directory."); + } + if (!cmd.hasOption(OPTION_CSV_PATH)) { + throw new IllegalArgumentException("Path to CSV-File need to be set."); + } + if (!cmd.hasOption(OPTION_OUTPUT_PATH)) { + throw new IllegalArgumentException("Define a graph output directory."); + } + if (!cmd.hasOption(OPTION_STATISTICS_PATH)) { + throw new IllegalArgumentException("Define a path to generated statistics."); + } + } + + /** + * Method to create and add lines to a csv-file + * + * @param env given ExecutionEnvironment + * @throws IOException exeption during file writing + */ + private static void writeCSV(ExecutionEnvironment env) throws IOException { + + String head = String.format("%s|%s|%s%n", + "Parallelism", + "dataset", + "Runtime(s)"); + + String tail = String.format("%s|%s|%s%n", + env.getParallelism(), + INPUT_PATH, + env.getLastJobExecutionResult().getNetRuntime(TimeUnit.SECONDS)); + + File f = new File(CSV_PATH); + if (f.exists() && !f.isDirectory()) { + FileUtils.writeStringToFile(f, tail, true); + } else { + PrintWriter writer = new PrintWriter(CSV_PATH, "UTF-8"); + writer.print(head); + writer.print(tail); + writer.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescription() { + return SocialNetworkAnalyticsExample.class.getName(); + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/CountFilter.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/CountFilter.java new file mode 100644 index 000000000000..5c394df186c4 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/CountFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.benchmark.sna.functions; + +import org.apache.flink.api.common.functions.FilterFunction; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.properties.PropertyValue; + +/** + * Filter all edges below a count of 500 + */ +public class CountFilter implements FilterFunction { + /** + * {@inheritDoc} + */ + @Override + public boolean filter(Edge edge) { + PropertyValue value = edge.getPropertyValue("count"); + return value.getLong() > 500; + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/package-info.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/package-info.java new file mode 100644 index 000000000000..0ddd3aedd302 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/functions/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains functions used in benchmark programs + */ +package org.gradoop.benchmark.sna.functions; diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/package-info.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/package-info.java new file mode 100644 index 000000000000..59712e15367f --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/sna/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains benchmark classes (social analytics) + */ +package org.gradoop.benchmark.sna; diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/SubgraphBenchmark.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/SubgraphBenchmark.java new file mode 100644 index 000000000000..59b8f7305077 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/SubgraphBenchmark.java @@ -0,0 +1,215 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.benchmark.subgraph; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.io.FileUtils; +import org.apache.flink.api.common.ProgramDescription; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.gradoop.examples.AbstractRunner; +import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.api.DataSource; +import org.gradoop.flink.io.impl.csv.CSVDataSink; +import org.gradoop.flink.io.impl.csv.indexed.IndexedCSVDataSource; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.functions.epgm.ByLabel; +import org.gradoop.flink.model.impl.operators.subgraph.Subgraph; +import org.gradoop.flink.util.GradoopFlinkConfig; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +/** + * A dedicated program for parametrized subgraph benchmark. + */ +public class SubgraphBenchmark extends AbstractRunner implements ProgramDescription { + /** + * Option to declare path to indexed input graph + */ + private static final String OPTION_INPUT_PATH = "i"; + /** + * Option to declare path to output graph + */ + private static final String OPTION_OUTPUT_PATH = "o"; + /** + * Option to declare output path to statistics csv file + */ + private static final String OPTION_CSV_PATH = "c"; + /** + * Option to declare verification + */ + private static final String OPTION_VERIFICATION = "v"; + /** + * Option to declare used vertex label + */ + private static final String OPTION_VERTEX_LABEL = "vl"; + /** + * Option to declare used edge label + */ + private static final String OPTION_EDGE_LABEL = "el"; + /** + * Used input path + */ + private static String INPUT_PATH; + /** + * Used output path + */ + private static String OUTPUT_PATH; + /** + * Used csv path + */ + private static String CSV_PATH; + /** + * Used vertex label + */ + private static String VERTEX_LABEL; + /** + * Used edge label + */ + private static String EDGE_LABEL; + /** + * Used verification flag + */ + private static boolean VERIFICATION; + + static { + OPTIONS.addOption(OPTION_INPUT_PATH, "input", true, + "Path to indexed source files."); + OPTIONS.addOption(OPTION_OUTPUT_PATH, "output", true, + "Path to output file"); + OPTIONS.addOption(OPTION_CSV_PATH, "csv", true, + "Path to csv statistics"); + OPTIONS.addOption(OPTION_VERIFICATION, "verification", false, + "Verify Subgraph with join."); + OPTIONS.addOption(OPTION_VERTEX_LABEL, "vertex-label", true, + "Used vertex label"); + OPTIONS.addOption(OPTION_EDGE_LABEL, "edge-label", true, + "Used edge label"); + } + + /** + * Main program to run the benchmark. Arguments are the available options. + * + * @param args program arguments + * @throws Exception in case of Error + */ + public static void main(String[] args) throws Exception { + CommandLine cmd = parseArguments(args, SubgraphBenchmark.class.getName()); + + if (cmd == null) { + System.exit(1); + } + + // test if minimum arguments are set + performSanityCheck(cmd); + + // read cmd arguments + readCMDArguments(cmd); + + // create gradoop config + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + GradoopFlinkConfig conf = GradoopFlinkConfig.createConfig(env); + + // read graph + DataSource source = new IndexedCSVDataSource(INPUT_PATH, conf); + LogicalGraph graph = source.getLogicalGraph(); + + // compute subgraph -> verify results (join) vs no verify (filter) + if (VERIFICATION) { + graph = graph.subgraph(new ByLabel<>(VERTEX_LABEL), new ByLabel<>(EDGE_LABEL), + Subgraph.Strategy.BOTH_VERIFIED); + } else { + graph = graph.subgraph(new ByLabel<>(VERTEX_LABEL), new ByLabel<>(EDGE_LABEL), + Subgraph.Strategy.BOTH); + } + + // write graph + DataSink sink = new CSVDataSink(OUTPUT_PATH, conf); + sink.write(graph); + + // execute and write job statistics + env.execute(); + writeCSV(env); + } + + /** + * Reads the given arguments from command line + * + * @param cmd command line + */ + private static void readCMDArguments(CommandLine cmd) { + INPUT_PATH = cmd.getOptionValue(OPTION_INPUT_PATH); + OUTPUT_PATH = cmd.getOptionValue(OPTION_OUTPUT_PATH); + CSV_PATH = cmd.getOptionValue(OPTION_CSV_PATH); + VERTEX_LABEL = cmd.getOptionValue(OPTION_VERTEX_LABEL); + EDGE_LABEL = cmd.getOptionValue(OPTION_EDGE_LABEL); + VERIFICATION = cmd.hasOption(OPTION_VERIFICATION); + } + + /** + * Checks if the minimum of arguments is provided + * + * @param cmd command line + */ + private static void performSanityCheck(CommandLine cmd) { + if (!cmd.hasOption(OPTION_INPUT_PATH)) { + throw new IllegalArgumentException("Define a graph input directory."); + } + if (!cmd.hasOption(OPTION_CSV_PATH)) { + throw new IllegalArgumentException("Path to CSV-File need to be set."); + } + if (!cmd.hasOption(OPTION_OUTPUT_PATH)) { + throw new IllegalArgumentException("Define a graph output directory."); + } + } + + /** + * Method to create and add lines to a csv-file + * + * @param env given ExecutionEnvironment + * @throws IOException exeption during file writing + */ + private static void writeCSV(ExecutionEnvironment env) throws IOException { + + String head = String + .format("%s|%s|%s|%s|%s|%s%n", "Parallelism", "dataset", "vertex-label", "edge-label", + "verification", "Runtime(s)"); + + String tail = String + .format("%s|%s|%s|%s|%s|%s%n", env.getParallelism(), INPUT_PATH, VERTEX_LABEL, EDGE_LABEL, + VERIFICATION, env.getLastJobExecutionResult().getNetRuntime(TimeUnit.SECONDS)); + + File f = new File(CSV_PATH); + if (f.exists() && !f.isDirectory()) { + FileUtils.writeStringToFile(f, tail, true); + } else { + PrintWriter writer = new PrintWriter(CSV_PATH, "UTF-8"); + writer.print(head); + writer.print(tail); + writer.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescription() { + return SubgraphBenchmark.class.getName(); + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/package-info.java b/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/package-info.java new file mode 100644 index 000000000000..dff2ad4e8a7a --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/benchmark/subgraph/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains benchmark classes (subgraph) + */ +package org.gradoop.benchmark.subgraph; diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/AbstractRunner.java b/gradoop-examples/src/main/java/org/gradoop/examples/AbstractRunner.java index 494a2fdc4b45..f62671a864fe 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/AbstractRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/AbstractRunner.java @@ -21,6 +21,8 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.flink.api.java.ExecutionEnvironment; +import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.api.DataSource; import org.gradoop.flink.io.impl.csv.CSVDataSink; import org.gradoop.flink.io.impl.csv.CSVDataSource; import org.gradoop.flink.io.impl.csv.indexed.IndexedCSVDataSink; @@ -42,6 +44,10 @@ public abstract class AbstractRunner { * Command line options for the runner. */ protected static final Options OPTIONS = new Options(); + /** + * Graph format used as default + */ + protected static final String DEFAULT_FORMAT = "csv"; /** * Flink execution environment. */ @@ -50,10 +56,10 @@ public abstract class AbstractRunner { /** * Parses the program arguments and performs sanity checks. * - * @param args program arguments + * @param args program arguments * @param className executing class name (for help display) * @return command line which can be used in the program - * @throws ParseException + * @throws ParseException on failure */ protected static CommandLine parseArguments(String[] args, String className) throws ParseException { @@ -66,85 +72,91 @@ protected static CommandLine parseArguments(String[] args, String className) } /** - * Reads an EPGM database from a given directory. + * Reads an EPGM database from a given directory using a {@link CSVDataSource}. * * @param directory path to EPGM database * @return EPGM logical graph */ - @SuppressWarnings("unchecked") protected static LogicalGraph readLogicalGraph(String directory) throws IOException { - return readLogicalGraph(directory, "json"); + return readLogicalGraph(directory, DEFAULT_FORMAT); } /** * Reads an EPGM database from a given directory. * * @param directory path to EPGM database - * @param format format in which the graph is stored (csv, json) + * @param format format in which the graph is stored (csv, indexed, json) * @return EPGM logical graph + * @throws IOException on failure */ - @SuppressWarnings("unchecked") protected static LogicalGraph readLogicalGraph(String directory, String format) throws IOException { - directory = appendSeparator(directory); - - GradoopFlinkConfig config = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); - format = format.toLowerCase(); + return getDataSource(directory, format).getLogicalGraph(); + } - if (format.equals("json")) { - return new JSONDataSource(directory, config).getLogicalGraph(); - } else if (format.equals("csv")) { - return new CSVDataSource(directory, config).getLogicalGraph(); - } else if (format.equals("indexed")) { - return new IndexedCSVDataSource(directory, config).getLogicalGraph(); - } else { - throw new IllegalArgumentException("Unsupported format: " + format); - } + /** + * Reads an EPGM database from a given directory. + * + * @param directory path to EPGM database + * @param format format in which the graph collection is stored (csv, indexed, json) + * @return EPGM graph collection + * @throws IOException on failure + */ + protected static GraphCollection readGraphCollection(String directory, String format) + throws IOException { + return getDataSource(directory, format).getGraphCollection(); } /** - * Writes a logical graph into the specified directory using a {@link JSONDataSink}. + * Writes a logical graph into the specified directory using a {@link CSVDataSink}. * - * @param graph logical graph + * @param graph logical graph * @param directory output path - * @throws Exception + * @throws Exception on failure */ protected static void writeLogicalGraph(LogicalGraph graph, String directory) throws Exception { - writeLogicalGraph(graph, directory, "json"); + writeLogicalGraph(graph, directory, DEFAULT_FORMAT); } /** * Writes a logical graph into a given directory. * - * @param graph logical graph + * @param graph logical graph * @param directory output path - * @param format output format (json, csv) - * @throws Exception + * @param format output format (csv, indexed, json) + * @throws Exception on failure */ protected static void writeLogicalGraph(LogicalGraph graph, String directory, String format) throws Exception { - - format = format.toLowerCase(); - if (format.equals("json")) { - graph.writeTo(new JSONDataSink(appendSeparator(directory), graph.getConfig())); - } else if (format.equals("csv")) { - graph.writeTo(new CSVDataSink(appendSeparator(directory), graph.getConfig())); - } else if (format.equals("indexed")) { - graph.writeTo(new IndexedCSVDataSink(appendSeparator(directory), graph.getConfig())); - } + graph.writeTo(getDataSink(directory, format, graph.getConfig())); getExecutionEnvironment().execute(); } /** - * Writes a graph collection into the specified directory using a {@link JSONDataSink}. + * Writes a graph collection into the specified directory using a {@link CSVDataSink}. * - * @param collection graph collection - * @param directory output path - * @throws Exception + * @param collection graph collection + * @param directory output path + * @throws Exception on failure */ protected static void writeGraphCollection(GraphCollection collection, String directory) throws Exception { - collection.writeTo(new JSONDataSink(appendSeparator(directory), collection.getConfig())); + writeGraphCollection(collection, directory, DEFAULT_FORMAT); + } + + /** + * Writes a graph collection into a given directory. + * + * @param collection graph collection + * @param directory output path + * @param format output format (csv, indexed, json) + * @throws Exception on failure + */ + protected static void writeGraphCollection(GraphCollection collection, + String directory, + String format) + throws Exception { + collection.writeTo(getDataSink(directory, format, collection.getConfig())); getExecutionEnvironment().execute(); } @@ -181,7 +193,7 @@ protected static String appendSeparator(final String directory) { * * @param dotFile path to DOT file * @param pngFile path to PNG file - * @throws IOException + * @throws IOException on failure */ protected static void convertDotToPNG(String dotFile, String pngFile) throws IOException { ProcessBuilder pb = new ProcessBuilder("dot", "-Tpng", dotFile); @@ -189,4 +201,53 @@ protected static void convertDotToPNG(String dotFile, String pngFile) throws IOE pb.redirectOutput(ProcessBuilder.Redirect.appendTo(output)); pb.start(); } + + /** + * Returns an EPGM DataSource for a given directory and format. + * + * @param directory input path + * @param format format in which the data is stored (csv, indexed, json) + * @return DataSource for EPGM Data + * @throws IOException on failure + */ + private static DataSource getDataSource(String directory, String format) throws IOException { + directory = appendSeparator(directory); + GradoopFlinkConfig config = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + format = format.toLowerCase(); + + switch (format) { + case "json": + return new JSONDataSource(directory, config); + case "csv": + return new CSVDataSource(directory, config); + case "indexed": + return new IndexedCSVDataSource(directory, config); + default: + throw new IllegalArgumentException("Unsupported format: " + format); + } + } + + /** + * Returns an EPGM DataSink for a given directory and format. + * + * @param directory output path + * @param format output format (csv, indexed, json) + * @param config gradoop config + * @return DataSink for EPGM Data + */ + private static DataSink getDataSink(String directory, String format, GradoopFlinkConfig config) { + directory = appendSeparator(directory); + format = format.toLowerCase(); + + switch (format) { + case "json": + return new JSONDataSink(directory, config); + case "csv": + return new CSVDataSink(directory, config); + case "indexed": + return new IndexedCSVDataSink(directory, config); + default: + throw new IllegalArgumentException("Unsupported format: " + format); + } + } } diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/AggregationExample.java b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/AggregationExample.java new file mode 100644 index 000000000000..93e1813cc6a6 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/AggregationExample.java @@ -0,0 +1,99 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.examples.aggregation; + +import org.apache.flink.api.java.ExecutionEnvironment; +import org.gradoop.examples.aggregation.functions.AddPropertyMeanAgeToGraphHead; +import org.gradoop.examples.aggregation.functions.AggregateListOfNames; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.functions.epgm.ByLabel; +import org.gradoop.flink.model.impl.operators.aggregation.functions.count.VertexCount; +import org.gradoop.flink.model.impl.operators.aggregation.functions.sum.SumVertexProperty; +import org.gradoop.flink.util.FlinkAsciiGraphLoader; +import org.gradoop.flink.util.GradoopFlinkConfig; + +/** + * A self contained example on how to use the aggregate operator on Gradoop's LogicalGraph class. + * + * The example uses the graph in dev-support/social-network.pdf + */ +public class AggregationExample { + + /** + * Path to the example data graph + */ + private static final String EXAMPLE_DATA_FILE = + AggregationExample.class.getResource("/data/gdl/sna.gdl").getFile(); + /** + * Property key 'birthday' + */ + private static final String PROPERTY_KEY_BIRTHDAY = "birthday"; + /** + * Property key 'person' + */ + private static final String LABEL_PERSON = "Person"; + + /** + * Runs the program on the example data graph. + * + * The example provides an overview over the usage of the aggregate() method. + * It both showcases the application of aggregation functions that are already provided by + * Gradoop, as well as the definition of custom ones. + * Documentation for all available aggregation functions as well as a detailed description of the + * aggregate method can be found in the projects wiki. + * + * @see + * Gradoop Wiki + * + * Using the social network graph in the resources directory, the program will: + * 1. extract a subgraph only containing vertices which are labeled "person" + * 2. concatenate the values of the vertex property "name" of each vertex in the subgraph + * 3. count the amount of vertices in the subgraph (aka the amount of persons) + * 4. sum up the values of the vertex property "birthday" + * 5. add the property "meanAge" to the graph head using a graph head transformation + * + * @param args arguments + */ + public static void main(String[] args) throws Exception { + // init execution environment + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + // create loader + FlinkAsciiGraphLoader loader = new FlinkAsciiGraphLoader(GradoopFlinkConfig.createConfig(env)); + + // load data + loader.initDatabaseFromFile(EXAMPLE_DATA_FILE); + + // get LogicalGraph representation of the social network graph + LogicalGraph networkGraph = loader.getDatabase().getDatabaseGraph(); + + // execute aggregations and graph-head transformations + LogicalGraph result = networkGraph + // extract subgraph with edges and vertices which are of interest + .vertexInducedSubgraph(new ByLabel<>(LABEL_PERSON)) + // apply custom VertexAggregateFunction + .aggregate(new AggregateListOfNames()) + // aggregate sum of vertices in order to obtain total amount of persons + .aggregate(new VertexCount()) + // sum up values of the vertex property "birthday" + .aggregate(new SumVertexProperty(PROPERTY_KEY_BIRTHDAY)) + // add computed property "meanAge" to the graph head + .transformGraphHead(new AddPropertyMeanAgeToGraphHead()); + + // print graph, which now contains the newly aggregated properties in the graph head + result.print(); + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AddPropertyMeanAgeToGraphHead.java b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AddPropertyMeanAgeToGraphHead.java new file mode 100644 index 000000000000..13a7e0f39512 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AddPropertyMeanAgeToGraphHead.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.examples.aggregation.functions; + +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.flink.model.api.functions.TransformationFunction; + +/** + * Custom graph head transformation function used in {@link org.gradoop.examples.aggregation.AggregationExample} + */ +public class AddPropertyMeanAgeToGraphHead implements TransformationFunction { + + /** + * Property key 'mean_age' + */ + private static final String PROPERTY_KEY_MEAN_AGE = "mean_age"; + + @Override + public GraphHead apply(GraphHead current, GraphHead transformed) { + // property 'sum_birthday' is result of the aggregate function SumVertexProperty + int sumAge = current.getPropertyValue("sum_birthday").getInt(); + // property 'vertexCount' is result of the aggregate function VertexCount + long numPerson = current.getPropertyValue("vertexCount").getLong(); + current.setProperty(PROPERTY_KEY_MEAN_AGE, (double) sumAge / numPerson); + return current; + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AggregateListOfNames.java b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AggregateListOfNames.java new file mode 100644 index 000000000000..df29edd46728 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/AggregateListOfNames.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.examples.aggregation.functions; + +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.PropertyValue; +import org.gradoop.flink.model.api.functions.VertexAggregateFunction; + + +/** + * Custom vertex aggregate function that stores all values of the property 'name' over a set of + * vertices as a comma separated list in a property named 'list_of_names'. + * Used in {@link org.gradoop.examples.aggregation.AggregationExample} + */ +public class AggregateListOfNames implements VertexAggregateFunction { + + /** + * Property key 'name' + */ + private static final String PROPERTY_KEY_NAME = "name"; + /** + * Property key 'list_of_names' + */ + private static final String PROPERTY_KEY_LIST_OF_NAMES = "list_of_names"; + + @Override + public PropertyValue getVertexIncrement(Vertex vertex) { + return PropertyValue.create(vertex.getPropertyValue(PROPERTY_KEY_NAME).toString()); + } + + @Override + public PropertyValue aggregate(PropertyValue aggregate, PropertyValue increment) { + aggregate.setString(aggregate.getString() + "," + increment.getString()); + return aggregate; + } + + @Override + public String getAggregatePropertyKey() { + return PROPERTY_KEY_LIST_OF_NAMES; + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/package-info.java b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/package-info.java new file mode 100644 index 000000000000..84928c05e994 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/functions/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Custom functions used in the {@link org.gradoop.examples.aggregation.AggregationExample}. + */ +package org.gradoop.examples.aggregation.functions; diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/package-info.java b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/package-info.java new file mode 100644 index 000000000000..332bda951b45 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/examples/aggregation/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Examples related to aggregation operators + */ +package org.gradoop.examples.aggregation; diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/biiig/FrequentLossPatterns.java b/gradoop-examples/src/main/java/org/gradoop/examples/biiig/FrequentLossPatterns.java index 1201fb91ef9d..a0ac37eea188 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/biiig/FrequentLossPatterns.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/biiig/FrequentLossPatterns.java @@ -26,7 +26,6 @@ import org.gradoop.flink.algorithms.fsm.TransactionalFSM; import org.gradoop.flink.algorithms.fsm.dimspan.config.DIMSpanConstants; import org.gradoop.flink.io.impl.dot.DOTDataSink; -import org.gradoop.flink.io.impl.json.JSONDataSource; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.functions.TransformationFunction; @@ -34,7 +33,6 @@ import org.gradoop.flink.model.impl.operators.aggregation.ApplyAggregation; import org.gradoop.flink.model.impl.operators.aggregation.functions.sum.Sum; import org.gradoop.flink.model.impl.operators.transformation.ApplyTransformation; -import org.gradoop.flink.util.GradoopFlinkConfig; import java.math.BigDecimal; @@ -141,33 +139,21 @@ private static GraphHead addSupportToGraphHead(GraphHead current, /** * main method * @param args arguments (none required) - * @throws Exception + * @throws Exception on failure */ public static void main(String[] args) throws Exception { // avoids multiple output files getExecutionEnvironment().setParallelism(1); - // get Gradoop configuration - GradoopFlinkConfig config = GradoopFlinkConfig - .createConfig(getExecutionEnvironment()); // START DEMONSTRATION PROGRAM // (1) read data from source - String graphHeadPath = FrequentLossPatterns.class - .getResource("/data/json/foodbroker/graphs.json").getFile(); + String csvPath = FrequentLossPatterns.class + .getResource("/data/csv/foodbroker").getFile(); - String vertexPath = FrequentLossPatterns.class. - getResource("/data/json/foodbroker/nodes.json").getFile(); - - String edgePath = FrequentLossPatterns.class - .getResource("/data/json/foodbroker/edges.json").getFile(); - - JSONDataSource dataSource = new JSONDataSource( - graphHeadPath, vertexPath, edgePath, config); - - LogicalGraph iig = dataSource.getLogicalGraph(); + LogicalGraph iig = readLogicalGraph(csvPath); // (2) extract collection of business transaction graphs diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/grouping/GroupingRunner.java b/gradoop-examples/src/main/java/org/gradoop/examples/grouping/GroupingRunner.java index 926976b5444a..7ae232e5e61b 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/grouping/GroupingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/grouping/GroupingRunner.java @@ -32,6 +32,10 @@ public class GroupingRunner extends AbstractRunner implements ProgramDescription * Option to declare path to input graph */ public static final String OPTION_INPUT_PATH = "i"; + /** + * Option to declare input graph format (csv, indexed, json) + */ + public static final String OPTION_INPUT_FORMAT = "f"; /** * Option to declare path to output graph */ @@ -56,6 +60,8 @@ public class GroupingRunner extends AbstractRunner implements ProgramDescription static { OPTIONS.addOption(OPTION_INPUT_PATH, "vertex-input-path", true, "Path to vertex file"); + OPTIONS.addOption(OPTION_INPUT_FORMAT, "input-format", true, + "Format of the input [csv, indexed, json]. Default: " + DEFAULT_FORMAT); OPTIONS.addOption(OPTION_OUTPUT_PATH, "output-path", true, "Path to write output files to"); OPTIONS.addOption(OPTION_VERTEX_GROUPING_KEY, "vertex-grouping-key", true, @@ -72,7 +78,7 @@ public class GroupingRunner extends AbstractRunner implements ProgramDescription * Main program to run the example. Arguments are the available options. * * @param args program arguments - * @throws Exception + * @throws Exception on failure */ @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { @@ -86,6 +92,9 @@ public static void main(String[] args) throws Exception { final String inputPath = cmd.getOptionValue(OPTION_INPUT_PATH); final String outputPath = cmd.getOptionValue(OPTION_OUTPUT_PATH); + final String inputFormat = cmd.hasOption(OPTION_INPUT_FORMAT) ? + cmd.getOptionValue(OPTION_INPUT_FORMAT) : DEFAULT_FORMAT; + boolean useVertexKey = cmd.hasOption(OPTION_VERTEX_GROUPING_KEY); String vertexKey = useVertexKey ? cmd.getOptionValue(OPTION_VERTEX_GROUPING_KEY) : null; @@ -96,7 +105,7 @@ public static void main(String[] args) throws Exception { boolean useEdgeLabels = cmd.hasOption(OPTION_USE_EDGE_LABELS); // initialize EPGM database - LogicalGraph graphDatabase = readLogicalGraph(inputPath); + LogicalGraph graphDatabase = readLogicalGraph(inputPath, inputFormat); // initialize grouping method Grouping grouping = getOperator( diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/io/DOTExample.java b/gradoop-examples/src/main/java/org/gradoop/examples/io/DOTExample.java index f4359ceead21..f606081e9cc4 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/io/DOTExample.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/io/DOTExample.java @@ -20,12 +20,10 @@ import org.gradoop.examples.AbstractRunner; import org.gradoop.flink.io.impl.dot.DOTDataSink; import org.gradoop.flink.io.impl.dot.functions.DOTFileFormat; -import org.gradoop.flink.io.impl.json.JSONDataSource; import org.gradoop.flink.model.api.epgm.GraphCollection; -import org.gradoop.flink.util.GradoopFlinkConfig; /** - * Example program that reads a graph from an EPGM-specific JSON representation + * Example program that reads a graph from an EPGM format (csv, indexed, json) * into a {@link GraphCollection} and stores the * resulting {@link GraphCollection} as DOT. * The resulting format is described in {@link DOTFileFormat}. @@ -36,11 +34,10 @@ public class DOTExample extends AbstractRunner implements ProgramDescription { * Reads an EPGM graph collection from a directory that contains the separate * files. Files can be stored in local file system or HDFS. * - * args[0]: path to graph head file - * args[1]: path to vertex file - * args[2]: path to edge file - * args[3]: path to write output graph - * args[4]: flag to write graph head information + * args[0]: path to graph files + * args[1]: input graph format + * args[2]: path to write output graph + * args[3]: flag to write graph head information * * @param args program arguments */ @@ -51,28 +48,23 @@ public static void main(String[] args) throws Exception { "graph head information (true/false)"); } - final String graphHeadFile = args[0]; - final String vertexFile = args[1]; - final String edgeFile = args[2]; - final String outputDir = args[3]; - final String graphHeadInformation = args[4]; + final String inputDir = args[0]; + final String inputFormat = args[1]; + final String outputDir = args[2]; + final String graphHeadInformation = args[3]; // init Flink execution environment ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); - // create default Gradoop config - GradoopFlinkConfig config = GradoopFlinkConfig.createConfig(env); - - // create DataSource - JSONDataSource dataSource = - new JSONDataSource(graphHeadFile, vertexFile, edgeFile, config); + // read graph collection + GraphCollection collection = readGraphCollection(inputDir, inputFormat); // create DataSink DOTDataSink dataSink = new DOTDataSink(outputDir, Boolean.parseBoolean(graphHeadInformation)); // write dot format - dataSink.write(dataSource.getGraphCollection()); + dataSink.write(collection); // execute program env.execute(); diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/CypherExample.java b/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/CypherExample.java index c6dbb9dd60d3..047b1b6cdecb 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/CypherExample.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/CypherExample.java @@ -16,8 +16,7 @@ package org.gradoop.examples.patternmatching; import org.apache.flink.api.java.ExecutionEnvironment; -import org.gradoop.flink.io.api.DataSource; -import org.gradoop.flink.io.impl.json.JSONDataSource; +import org.gradoop.flink.io.impl.csv.CSVDataSource; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatistics; @@ -33,7 +32,7 @@ public class CypherExample { /** * Path to the data graph. */ - static final String DATA_PATH = CypherExample.class.getResource("/data/json/sna").getFile(); + static final String DATA_PATH = CypherExample.class.getResource("/data/csv/sna").getFile(); /** * Path to the data graph statistics (computed using {@link org.gradoop.utils.statistics.StatisticsRunner} */ @@ -52,12 +51,12 @@ public static void main(String[] args) throws Exception { // create a Gradoop config GradoopFlinkConfig config = GradoopFlinkConfig.createConfig(env); // create a datasource - DataSource jsonDataSource = new JSONDataSource(DATA_PATH, config); + CSVDataSource csvDataSource = new CSVDataSource(DATA_PATH, config); // load graph statistics GraphStatistics statistics = GraphStatisticsLocalFSReader.read(STATISTICS_PATH); // load graph from datasource (lazy) - LogicalGraph socialNetwork = jsonDataSource.getLogicalGraph(); + LogicalGraph socialNetwork = csvDataSource.getLogicalGraph(); // run a Cypher query (vertex homomorphism, edge isomorphism) // the result is a graph collection containing all matching subgraphs diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/PatternMatchingRunner.java b/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/PatternMatchingRunner.java index bde71a62c11a..400e1b473b68 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/PatternMatchingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/patternmatching/PatternMatchingRunner.java @@ -77,7 +77,7 @@ public class PatternMatchingRunner extends AbstractRunner implements ProgramDesc */ private static final String OPTION_INPUT_PATH = "i"; /** - * Option to declare the format of the input path (csv,json) + * Option to declare input graph format (csv, indexed, json) */ private static final String OPTION_INPUT_FORMAT = "f"; /** @@ -105,7 +105,7 @@ public class PatternMatchingRunner extends AbstractRunner implements ProgramDesc OPTIONS.addOption(OPTION_INPUT_PATH, "input-path", true, "Input graph directory"); OPTIONS.addOption(OPTION_INPUT_FORMAT, "input-format", true, - "Format of the input graph [csv,json]"); + "Format of the input graph [csv, indexed, json]"); OPTIONS.addOption(OPTION_OUTPUT_PATH, "output-path", true, "Output graph directory"); OPTIONS.addOption(OPTION_QUERY_GRAPH, "query", true, @@ -123,7 +123,7 @@ public class PatternMatchingRunner extends AbstractRunner implements ProgramDesc * Runs the simulation using the given arguments. *

* -i, --input-path (path to data graph)
- * -f, --input-format (format of data graph [json,csv])
+ * -f, --input-format (format of data graph [csv, indexed, json])
* -o, --output-path (path to output directory)
* -q, --query (GDL/Cypher query string)
* -a, --algorithm [dual-bulk,dual-delta,iso-exp,iso-exp-bc-hf,cypher]
diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark1.java b/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark1.java index fbc8eae20e4c..3e8347015173 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark1.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark1.java @@ -43,14 +43,12 @@ public class SNABenchmark1 extends AbstractRunner implements /** * Runs the example program. * - * Need a (possibly HDFS) input directory that contains - * - nodes.json - * - edges.json - * - graphs.json + * Need a (possibly HDFS) input directory that contains a EPGM graph + * in a given format (csv, indexed, json) * * Needs a (possibly HDFS) output directory to write the resulting graph to. * - * @param args args[0] = input dir, args[1] output dir + * @param args args[0] = input dir, args[1] input format, args[2] output dir * @throws Exception */ @SuppressWarnings({ @@ -59,11 +57,12 @@ public class SNABenchmark1 extends AbstractRunner implements }) public static void main(String[] args) throws Exception { Preconditions.checkArgument( - args.length == 2, "input dir and output dir required"); + args.length == 3, "input dir, input format and output dir required"); String inputDir = args[0]; - String outputDir = args[1]; + String inputFormat = args[1]; + String outputDir = args[2]; - LogicalGraph epgmDatabase = readLogicalGraph(inputDir); + LogicalGraph epgmDatabase = readLogicalGraph(inputDir, inputFormat); LogicalGraph result = execute(epgmDatabase); diff --git a/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark2.java b/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark2.java index 3fc13c3a1d6f..ecd630d4e2e1 100644 --- a/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark2.java +++ b/gradoop-examples/src/main/java/org/gradoop/examples/sna/SNABenchmark2.java @@ -66,14 +66,13 @@ public class SNABenchmark2 extends AbstractRunner implements * * For using external data, the following arguments are mandatory: * - * 1) (possibly HDFS) input directory that contains - * - nodes.json - * - edges.json - * - graphs.json + * 1) (possibly HDFS) input directory that contains a EPGM graph * - * 2) (possibly HDFS) output directory to write the resulting graph to + * 2) Format the graph is in (csv, indexed, json) * - * 3) Threshold for community selection depending on the dataset size: + * 3) (possibly HDFS) output directory to write the resulting graph to + * + * 4) Threshold for community selection depending on the dataset size: * * Scale - Threshold (recommended) * 1 - 1,000 @@ -82,7 +81,7 @@ public class SNABenchmark2 extends AbstractRunner implements * 1K - 350,000 * 10K - 2,450,000 * - * @param args args[0]: input dir, args[1]: output dir, args[2]: threshold + * @param args args[0]: input dir, args[1]: input format, args[2]: output dir, args[3]: threshold * @throws Exception */ @SuppressWarnings({ @@ -103,23 +102,24 @@ public static void main(String[] args) throws Exception { /** * Runs the benchmark program with external data (e.g. from HDFS) + * in a given format (csv, indexed, json) * - * @param args args[0]: input dir, args[1]: output dir, args[2]: threshold + * @param args args[0]: input dir, args[1]: input format, args[2]: output dir, args[3]: threshold * @throws Exception */ @SuppressWarnings("unchecked") private static void executeWithExternalData(String[] args) throws Exception { Preconditions.checkArgument( - args.length == 3, "input dir, output dir and threshold required"); - String inputDir = args[0]; - String outputDir = args[1]; - int threshold = Integer.parseInt(args[2]); + args.length == 4, + "input dir, input format, output dir and threshold required"); + String inputDir = args[0]; + String inputFormat = args[1]; + String outputDir = args[2]; + int threshold = Integer.parseInt(args[3]); - LogicalGraph epgmDatabase = readLogicalGraph(inputDir); + LogicalGraph epgmDatabase = readLogicalGraph(inputDir, inputFormat); writeLogicalGraph(execute(epgmDatabase, threshold), outputDir); - - getExecutionEnvironment().execute(); } /** diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomEdgeSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomEdgeSamplingRunner.java index 61dfcbcd510f..b738c5d2e523 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomEdgeSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomEdgeSamplingRunner.java @@ -40,7 +40,9 @@ public class RandomEdgeSamplingRunner extends AbstractRunner implements ProgramD */ public static void main(String[] args) throws Exception { LogicalGraph graph = readLogicalGraph(args[0], args[1]); + LogicalGraph sample = graph.callForGraph(new RandomEdgeSampling(Float.parseFloat(args[4]))); + writeLogicalGraph(sample, args[2], args[3]); } diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomLimitedDegreeVertexSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomLimitedDegreeVertexSamplingRunner.java index 9fc5e1c45d31..3573caf87841 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomLimitedDegreeVertexSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomLimitedDegreeVertexSamplingRunner.java @@ -38,14 +38,17 @@ public class RandomLimitedDegreeVertexSamplingRunner extends AbstractRunner impl * args[3] - format of output graph (csv, json, indexed) * args[4] - sampling threshold * args[5] - vertex degree threshold - * args[6] - vertex degree type (IN, OUT, IN_OUT) + * args[6] - vertex degree type (IN, OUT, BOTH) * * @param args arguments */ public static void main(String[] args) throws Exception { LogicalGraph graph = readLogicalGraph(args[0], args[1]); - LogicalGraph sample = graph.callForGraph(new RandomLimitedDegreeVertexSampling( - Float.parseFloat(args[4]), Long.parseLong(args[5]), VertexDegree.valueOf(args[6]))); + + LogicalGraph sample = graph.callForGraph( + new RandomLimitedDegreeVertexSampling( + Float.parseFloat(args[4]), Long.parseLong(args[5]), VertexDegree.valueOf(args[6]))); + writeLogicalGraph(sample, args[2], args[3]); } diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomNonUniformVertexSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomNonUniformVertexSamplingRunner.java index 9a57c7dcb098..7e1763807568 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomNonUniformVertexSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomNonUniformVertexSamplingRunner.java @@ -40,8 +40,10 @@ public class RandomNonUniformVertexSamplingRunner extends AbstractRunner impleme */ public static void main(String[] args) throws Exception { LogicalGraph graph = readLogicalGraph(args[0], args[1]); + LogicalGraph sample = graph.callForGraph( - new RandomNonUniformVertexSampling(Float.parseFloat(args[4]))); + new RandomNonUniformVertexSampling(Float.parseFloat(args[4]))); + writeLogicalGraph(sample, args[2], args[3]); } diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexEdgeSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexEdgeSamplingRunner.java index 122788a12258..e91f0c32f87e 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexEdgeSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexEdgeSamplingRunner.java @@ -36,16 +36,19 @@ public class RandomVertexEdgeSamplingRunner extends AbstractRunner implements Pr * args[3] - format of output graph (csv, json, indexed) * args[4] - sampling threshold for vertices * args[5] - sampling threshold for edges - * args[6] - sampling type + * args[6] - sampling type (SimpleVersion, NonuniformVersion, NonuniformHybridVersion) * * @param args arguments */ public static void main(String[] args) throws Exception { RandomVertexEdgeSampling.VertexEdgeSamplingType vertexEdgeSamplingType = - RandomVertexEdgeSampling.sampleTypeFromString(args[6]); + RandomVertexEdgeSampling.VertexEdgeSamplingType.valueOf(args[6]); + LogicalGraph graph = readLogicalGraph(args[0], args[1]); + LogicalGraph sample = graph.callForGraph(new RandomVertexEdgeSampling( - Float.parseFloat(args[4]), Float.parseFloat(args[5]), vertexEdgeSamplingType)); + Float.parseFloat(args[4]), Float.parseFloat(args[5]), vertexEdgeSamplingType)); + writeLogicalGraph(sample, args[2], args[3]); } diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexNeighborhoodSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexNeighborhoodSamplingRunner.java index f2f45152f25b..a8fc7d3a4482 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexNeighborhoodSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexNeighborhoodSamplingRunner.java @@ -21,8 +21,6 @@ import org.gradoop.flink.model.impl.operators.sampling.RandomVertexNeighborhoodSampling; import org.gradoop.flink.model.impl.operators.sampling.functions.Neighborhood; -import java.security.InvalidParameterException; - /** * Runs {@link RandomVertexNeighborhoodSampling} for a given * graph and writes the sampled output. @@ -38,32 +36,20 @@ public class RandomVertexNeighborhoodSamplingRunner extends AbstractRunner imple * args[2] - path to output graph * args[3] - format of output graph (csv, json, indexed) * args[4] - sampling threshold - * args[5] - type of neighborhood (input, output, both) + * args[5] - type of neighborhood (IN, OUT, BOTH) * * @param args arguments */ public static void main(String[] args) throws Exception { - Neighborhood.NeighborType neighborType; - String neighborhood = args[5]; - if (neighborhood.equals(Neighborhood.NeighborType.Input.toString())) { - neighborType = Neighborhood.NeighborType.Input; - } else if (neighborhood.equals(Neighborhood.NeighborType.Output.toString())) { - neighborType = Neighborhood.NeighborType.Output; - } else if (neighborhood.equals(Neighborhood.NeighborType.Both.toString())) { - neighborType = Neighborhood.NeighborType.Both; - } else { - throw new InvalidParameterException(); - } LogicalGraph graph = readLogicalGraph(args[0], args[1]); - LogicalGraph sample = - new RandomVertexNeighborhoodSampling(Float.parseFloat(args[4]), neighborType) - .execute(graph); + + LogicalGraph sample = graph.callForGraph( + new RandomVertexNeighborhoodSampling( + Float.parseFloat(args[4]), Neighborhood.valueOf(args[5]))); + writeLogicalGraph(sample, args[2], args[3]); } - /** - * {@inheritDoc} - */ @Override public String getDescription() { return RandomVertexNeighborhoodSamplingRunner.class.getName(); diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexSamplingRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexSamplingRunner.java index 401bac16e9d0..83b12471fc32 100644 --- a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexSamplingRunner.java +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/RandomVertexSamplingRunner.java @@ -40,7 +40,9 @@ public class RandomVertexSamplingRunner extends AbstractRunner implements Progra */ public static void main(String[] args) throws Exception { LogicalGraph graph = readLogicalGraph(args[0], args[1]); + LogicalGraph sample = graph.callForGraph(new RandomVertexSampling(Float.parseFloat(args[4]))); + writeLogicalGraph(sample, args[2], args[3]); } diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/GraphDensityRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/GraphDensityRunner.java new file mode 100644 index 000000000000..e3f1c107bab1 --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/GraphDensityRunner.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.utils.sampling.statistics; + +import org.apache.flink.api.common.ProgramDescription; +import org.apache.flink.api.java.DataSet; +import org.gradoop.examples.AbstractRunner; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.functions.tuple.ObjectTo1; +import org.gradoop.flink.model.impl.operators.sampling.statistics.GraphDensity; +import org.gradoop.flink.model.impl.operators.sampling.statistics.SamplingEvaluationConstants; +import org.gradoop.flink.model.impl.operators.statistics.writer.StatisticWriter; + +/** + * Calls the graph density computation for a logical graph. + * Writes the result to a csv-file named {@value SamplingEvaluationConstants#FILE_DENSITY} in + * the output directory, containing a single line with the graph density value, e.g.: + * + * BOF + * 0.281 + * EOF + */ +public class GraphDensityRunner extends AbstractRunner implements ProgramDescription { + + /** + * Calls the graph density computation for the graph. + * + * args[0] - path to graph + * args[1] - format of graph (csv, json, indexed) + * args[2] - output path + * + * @param args command line arguments + * @throws Exception in case of read/write failure + */ + public static void main(String[] args) throws Exception { + + LogicalGraph graph = readLogicalGraph(args[0], args[1]); + + DataSet density = graph.callForGraph(new GraphDensity()).getGraphHead() + .map(gh -> gh.getPropertyValue(SamplingEvaluationConstants.PROPERTY_KEY_DENSITY).getDouble()); + + StatisticWriter.writeCSV(density.map(new ObjectTo1<>()), + appendSeparator(args[2]) + SamplingEvaluationConstants.FILE_DENSITY); + + getExecutionEnvironment().execute("Sampling Statistics: Graph density"); + } + + @Override + public String getDescription() { + return GraphDensityRunner.class.getName(); + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/SamplingStatisticsRunner.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/SamplingStatisticsRunner.java new file mode 100644 index 000000000000..0ed4468ec5ad --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/SamplingStatisticsRunner.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.utils.sampling.statistics; + +import org.apache.flink.api.common.ProgramDescription; +import org.gradoop.examples.AbstractRunner; + +/** + * Calls the computation of all given graph properties for a logical graph. Results are written + * to files in the output path. + */ +public class SamplingStatisticsRunner extends AbstractRunner implements ProgramDescription { + + /** + * Calls the computation of all given graph properties. + * (List of called graph properties will be extended over time) + * + * args[0] - path to graph + * args[1] - format of graph (csv, json, indexed) + * args[2] - output path + * + * @param args command line arguments + * @throws Exception if something goes wrong + */ + public static void main(String[] args) throws Exception { + GraphDensityRunner.main(args); + } + + @Override + public String getDescription() { + return "Sampling Statistics"; + } +} diff --git a/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/package-info.java b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/package-info.java new file mode 100644 index 000000000000..0a9ae623b2ca --- /dev/null +++ b/gradoop-examples/src/main/java/org/gradoop/utils/sampling/statistics/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains sampling statistics runner + */ +package org.gradoop.utils.sampling.statistics; diff --git a/gradoop-examples/src/main/resources/data/csv/foodbroker/edges.csv b/gradoop-examples/src/main/resources/data/csv/foodbroker/edges.csv new file mode 100644 index 000000000000..5c614753bc52 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/foodbroker/edges.csv @@ -0,0 +1,1892 @@ +584a81be8fddee4a8ac1d39d;584a81be8fddee4a8ac1d399;584a81be8fddee4a8ac1cd99;PurchOrderLine;6.99|9|584a81be8fddee4a8ac1d398|T +584a81be8fddee4a8ac1d75b;584a81be8fddee4a8ac1d757;584a81be8fddee4a8ac1cda8;PurchOrderLine;2.2|51|584a81be8fddee4a8ac1d756|T +584a81be8fddee4a8ac1cf00;584a81be8fddee4a8ac1cefc;584a81be8fddee4a8ac1cdb1;PurchOrderLine;7.3|13|584a81be8fddee4a8ac1cefb|T +584a81be8fddee4a8ac1d017;584a81be8fddee4a8ac1d013;584a81be8fddee4a8ac1cdc3;PurchOrderLine;3.45|41|584a81be8fddee4a8ac1d012|T +584a81be8fddee4a8ac1d692;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1cdb3;PurchOrderLine;7.54|25|584a81be8fddee4a8ac1d68d|T +584a81be8fddee4a8ac1d2ec;584a81be8fddee4a8ac1d2e8;584a81be8fddee4a8ac1cdc7;PurchOrderLine;4.23|43|584a81be8fddee4a8ac1d2e7|T +584a81be8fddee4a8ac1d5f8;584a81be8fddee4a8ac1d5f4;584a81be8fddee4a8ac1cd97;PurchOrderLine;4.66|100|584a81be8fddee4a8ac1d5f3|T +584a81be8fddee4a8ac1d49e;584a81be8fddee4a8ac1d49a;584a81be8fddee4a8ac1cda7;PurchOrderLine;6.51|51|584a81be8fddee4a8ac1d499|T +584a81be8fddee4a8ac1d771;584a81be8fddee4a8ac1d76d;584a81be8fddee4a8ac1cdc8;PurchOrderLine;3.94|84|584a81be8fddee4a8ac1d76c|T +584a81be8fddee4a8ac1d67c;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1cda6;PurchOrderLine;8.24|15|584a81be8fddee4a8ac1d677|T +584a81be8fddee4a8ac1d5e2;584a81be8fddee4a8ac1d5de;584a81be8fddee4a8ac1cdc2;PurchOrderLine;5.17|97|584a81be8fddee4a8ac1d5dd|T +584a81be8fddee4a8ac1d001;584a81be8fddee4a8ac1cffd;584a81be8fddee4a8ac1cdaf;PurchOrderLine;7.39|75|584a81be8fddee4a8ac1cffc|T +584a81be8fddee4a8ac1d08f;584a81be8fddee4a8ac1d08b;584a81be8fddee4a8ac1cdc4;PurchOrderLine;9.72|26|584a81be8fddee4a8ac1d08a|T +584a81be8fddee4a8ac1d692;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1cdb3;PurchOrderLine;7.54|25|584a81be8fddee4a8ac1d68d|T +584a81be8fddee4a8ac1d452;584a81be8fddee4a8ac1d44e;584a81be8fddee4a8ac1cd97;PurchOrderLine;4.66|64|584a81be8fddee4a8ac1d44d|T +584a81be8fddee4a8ac1cea3;584a81be8fddee4a8ac1ce9f;584a81be8fddee4a8ac1cdc3;PurchOrderLine;3.39|5|584a81be8fddee4a8ac1ce9e|T +584a81be8fddee4a8ac1cfbf;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cdbf;PurchOrderLine;8.37|69|584a81be8fddee4a8ac1cfba|T +584a81be8fddee4a8ac1d13d;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1cdb2;PurchOrderLine;2.99|40|584a81be8fddee4a8ac1d138|T +584a81be8fddee4a8ac1d43c;584a81be8fddee4a8ac1d438;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|68|584a81be8fddee4a8ac1d437|T +584a81be8fddee4a8ac1d5c7;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|85|584a81be8fddee4a8ac1d5c2|T +584a81be8fddee4a8ac1d1da;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1cdb1;PurchOrderLine;7.44|54|584a81be8fddee4a8ac1d1d5|T +584a81be8fddee4a8ac1d7fa;584a81be8fddee4a8ac1d7f6;584a81be8fddee4a8ac1cda6;PurchOrderLine;8.08|99|584a81be8fddee4a8ac1d7f5|T +584a81be8fddee4a8ac1d55b;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1cda8;PurchOrderLine;2.2|26|584a81be8fddee4a8ac1d556|T +584a81be8fddee4a8ac1d107;584a81be8fddee4a8ac1d103;584a81be8fddee4a8ac1cd97;PurchOrderLine;4.47|52|584a81be8fddee4a8ac1d102|T +584a81be8fddee4a8ac1d6e3;584a81be8fddee4a8ac1d6df;584a81be8fddee4a8ac1cdba;PurchOrderLine;4.37|66|584a81be8fddee4a8ac1d6de|T +584a81be8fddee4a8ac1d3e4;584a81be8fddee4a8ac1d3e0;584a81be8fddee4a8ac1cda0;PurchOrderLine;8.76|46|584a81be8fddee4a8ac1d3df|T +584a81be8fddee4a8ac1ced4;584a81be8fddee4a8ac1ced0;584a81be8fddee4a8ac1cdaa;PurchOrderLine;0.78|11|584a81be8fddee4a8ac1cecf|T +584a81be8fddee4a8ac1cf2c;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cdb9;PurchOrderLine;7.18|81|584a81be8fddee4a8ac1cf27|T +584a81be8fddee4a8ac1d27e;584a81be8fddee4a8ac1d27a;584a81be8fddee4a8ac1cdcb;PurchOrderLine;6.94|42|584a81be8fddee4a8ac1d279|T +584a81be8fddee4a8ac1ceb9;584a81be8fddee4a8ac1ceb5;584a81be8fddee4a8ac1cdc1;PurchOrderLine;0.81|88|584a81be8fddee4a8ac1ceb4|T +584a81be8fddee4a8ac1cf2c;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cdb9;PurchOrderLine;7.18|81|584a81be8fddee4a8ac1cf27|T +584a81be8fddee4a8ac1d6cd;584a81be8fddee4a8ac1d6c9;584a81be8fddee4a8ac1cdc8;PurchOrderLine;4.02|69|584a81be8fddee4a8ac1d6c8|T +584a81be8fddee4a8ac1d13d;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1cdb2;PurchOrderLine;2.99|40|584a81be8fddee4a8ac1d138|T +584a81be8fddee4a8ac1d5c7;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|85|584a81be8fddee4a8ac1d5c2|T +584a81be8fddee4a8ac1cf73;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cdbc;PurchOrderLine;6.95|83|584a81be8fddee4a8ac1cf6e|T +584a81be8fddee4a8ac1d488;584a81be8fddee4a8ac1d484;584a81be8fddee4a8ac1cda0;PurchOrderLine;8.76|62|584a81be8fddee4a8ac1d483|T +584a81be8fddee4a8ac1d30c;584a81be8fddee4a8ac1d308;584a81be8fddee4a8ac1cda9;PurchOrderLine;1.48|88|584a81be8fddee4a8ac1d307|T +584a81be8fddee4a8ac1ceea;584a81be8fddee4a8ac1cee6;584a81be8fddee4a8ac1cdc8;PurchOrderLine;4.02|80|584a81be8fddee4a8ac1cee5|T +584a81be8fddee4a8ac1d468;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1cdc6;PurchOrderLine;0.59|95|584a81be8fddee4a8ac1d463|T +584a81be8fddee4a8ac1d740;584a81be8fddee4a8ac1d73c;584a81be8fddee4a8ac1cdbd;PurchOrderLine;0.75|35|584a81be8fddee4a8ac1d73b|T +584a81be8fddee4a8ac1d1c4;584a81be8fddee4a8ac1d1c0;584a81be8fddee4a8ac1cdad;PurchOrderLine;1.31|11|584a81be8fddee4a8ac1d1bf|T +584a81be8fddee4a8ac1d167;584a81be8fddee4a8ac1d163;584a81be8fddee4a8ac1cdba;PurchOrderLine;4.2|61|584a81be8fddee4a8ac1d162|T +584a81be8fddee4a8ac1d327;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|62|584a81be8fddee4a8ac1d322|T +584a81be8fddee4a8ac1d3b8;584a81be8fddee4a8ac1d3b4;584a81be8fddee4a8ac1cdb6;PurchOrderLine;5.15|49|584a81be8fddee4a8ac1d3b3|T +584a81be8fddee4a8ac1cf8e;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.2|15|584a81be8fddee4a8ac1cf89|T +584a81be8fddee4a8ac1d5a2;584a81be8fddee4a8ac1d59e;584a81be8fddee4a8ac1cdb6;PurchOrderLine;5.05|57|584a81be8fddee4a8ac1d59d|T +584a81be8fddee4a8ac1d048;584a81be8fddee4a8ac1d044;584a81be8fddee4a8ac1cdb6;PurchOrderLine;5.05|77|584a81be8fddee4a8ac1d043|T +584a81be8fddee4a8ac1d0a5;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1cda9;PurchOrderLine;1.53|67|584a81be8fddee4a8ac1d0a0|T +584a81be8fddee4a8ac1d2aa;584a81be8fddee4a8ac1d2a6;584a81be8fddee4a8ac1cda6;PurchOrderLine;7.92|35|584a81be8fddee4a8ac1d2a5|T +584a81be8fddee4a8ac1d426;584a81be8fddee4a8ac1d422;584a81be8fddee4a8ac1cd98;PurchOrderLine;4.61|12|584a81be8fddee4a8ac1d421|T +584a81be8fddee4a8ac1cf73;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cdbc;PurchOrderLine;6.95|83|584a81be8fddee4a8ac1cf6e|T +584a81be8fddee4a8ac1d650;584a81be8fddee4a8ac1d64c;584a81be8fddee4a8ac1cdcb;PurchOrderLine;6.66|48|584a81be8fddee4a8ac1d64b|T +584a81be8fddee4a8ac1d58c;584a81be8fddee4a8ac1d588;584a81be8fddee4a8ac1cdcb;PurchOrderLine;6.94|4|584a81be8fddee4a8ac1d587|T +584a81be8fddee4a8ac1d063;584a81be8fddee4a8ac1d05f;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.2|21|584a81be8fddee4a8ac1d05e|T +584a81be8fddee4a8ac1d4c3;584a81be8fddee4a8ac1d4bf;584a81be8fddee4a8ac1cda8;PurchOrderLine;2.29|61|584a81be8fddee4a8ac1d4be|T +584a81be8fddee4a8ac1d79d;584a81be8fddee4a8ac1d799;584a81be8fddee4a8ac1cd9c;PurchOrderLine;9.21|88|584a81be8fddee4a8ac1d798|T +584a81be8fddee4a8ac1d33d;584a81be8fddee4a8ac1d339;584a81be8fddee4a8ac1cd9d;PurchOrderLine;2.98|88|584a81be8fddee4a8ac1d338|T +584a81be8fddee4a8ac1d3fa;584a81be8fddee4a8ac1d3f6;584a81be8fddee4a8ac1cd9d;PurchOrderLine;2.86|54|584a81be8fddee4a8ac1d3f5|T +584a81be8fddee4a8ac1d0f1;584a81be8fddee4a8ac1d0ed;584a81be8fddee4a8ac1cda4;PurchOrderLine;9.01|28|584a81be8fddee4a8ac1d0ec|T +584a81be8fddee4a8ac1d079;584a81be8fddee4a8ac1d075;584a81be8fddee4a8ac1cdb8;PurchOrderLine;0.78|27|584a81be8fddee4a8ac1d074|T +584a81be8fddee4a8ac1d666;584a81be8fddee4a8ac1d662;584a81be8fddee4a8ac1cdbf;PurchOrderLine;8.21|72|584a81be8fddee4a8ac1d661|T +584a81be8fddee4a8ac1cf8e;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.2|15|584a81be8fddee4a8ac1cf89|T +584a81be8fddee4a8ac1d576;584a81be8fddee4a8ac1d572;584a81be8fddee4a8ac1cdb7;PurchOrderLine;1.99|12|584a81be8fddee4a8ac1d571|T +584a81be8fddee4a8ac1d67c;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1cda6;PurchOrderLine;8.24|15|584a81be8fddee4a8ac1d677|T +584a81be8fddee4a8ac1d7b3;584a81be8fddee4a8ac1d7af;584a81be8fddee4a8ac1cdb8;PurchOrderLine;0.77|34|584a81be8fddee4a8ac1d7ae|T +584a81be8fddee4a8ac1d0c0;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1cdc2;PurchOrderLine;5.17|89|584a81be8fddee4a8ac1d0bb|T +584a81be8fddee4a8ac1d410;584a81be8fddee4a8ac1d40c;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.25|87|584a81be8fddee4a8ac1d40b|T +584a81be8fddee4a8ac1d17d;584a81be8fddee4a8ac1d179;584a81be8fddee4a8ac1cdac;PurchOrderLine;1.7|51|584a81be8fddee4a8ac1d178|T +584a81be8fddee4a8ac1d1da;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1cdb1;PurchOrderLine;7.44|54|584a81be8fddee4a8ac1d1d5|T +584a81be8fddee4a8ac1d1ae;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1cd98;PurchOrderLine;4.8|13|584a81be8fddee4a8ac1d1a9|T +584a81be8fddee4a8ac1cfeb;584a81be8fddee4a8ac1cfe7;584a81be8fddee4a8ac1cda3;PurchOrderLine;1.74|17|584a81be8fddee4a8ac1cfe6|T +584a81be8fddee4a8ac1d032;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1cdb1;PurchOrderLine;7.59|90|584a81be8fddee4a8ac1d02d|T +584a81be8fddee4a8ac1d2c0;584a81be8fddee4a8ac1d2bc;584a81be8fddee4a8ac1cdc1;PurchOrderLine;0.79|59|584a81be8fddee4a8ac1d2bb|T +584a81be8fddee4a8ac1d468;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1cdc6;PurchOrderLine;0.59|95|584a81be8fddee4a8ac1d463|T +584a81be8fddee4a8ac1d2d6;584a81be8fddee4a8ac1d2d2;584a81be8fddee4a8ac1cda9;PurchOrderLine;1.5|11|584a81be8fddee4a8ac1d2d1|T +584a81be8fddee4a8ac1d358;584a81be8fddee4a8ac1d354;584a81be8fddee4a8ac1cd9a;PurchOrderLine;7.34|4|584a81be8fddee4a8ac1d353|T +584a81be8fddee4a8ac1d1f0;584a81be8fddee4a8ac1d1ec;584a81be8fddee4a8ac1cda6;PurchOrderLine;8.4|59|584a81be8fddee4a8ac1d1eb|T +584a81be8fddee4a8ac1d7c9;584a81be8fddee4a8ac1d7c5;584a81be8fddee4a8ac1cdb3;PurchOrderLine;7.69|49|584a81be8fddee4a8ac1d7c4|T +584a81be8fddee4a8ac1cfa4;584a81be8fddee4a8ac1cfa0;584a81be8fddee4a8ac1cdbc;PurchOrderLine;6.81|7|584a81be8fddee4a8ac1cf9f|T +584a81be8fddee4a8ac1d6f9;584a81be8fddee4a8ac1d6f5;584a81be8fddee4a8ac1cda7;PurchOrderLine;6.38|40|584a81be8fddee4a8ac1d6f4|T +584a81be8fddee4a8ac1d55b;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1cda8;PurchOrderLine;2.2|26|584a81be8fddee4a8ac1d556|T +584a81be8fddee4a8ac1d6ad;584a81be8fddee4a8ac1d6a9;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.34|20|584a81be8fddee4a8ac1d6a8|T +584a81be8fddee4a8ac1d1ae;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1cd98;PurchOrderLine;4.8|13|584a81be8fddee4a8ac1d1a9|T +584a81be8fddee4a8ac1d545;584a81be8fddee4a8ac1d541;584a81be8fddee4a8ac1cdba;PurchOrderLine;4.12|100|584a81be8fddee4a8ac1d540|T +584a81be8fddee4a8ac1d787;584a81be8fddee4a8ac1d783;584a81be8fddee4a8ac1cdc6;PurchOrderLine;0.61|72|584a81be8fddee4a8ac1d782|T +584a81be8fddee4a8ac1d232;584a81be8fddee4a8ac1d22e;584a81be8fddee4a8ac1cd98;PurchOrderLine;4.7|66|584a81be8fddee4a8ac1d22d|T +584a81be8fddee4a8ac1cf5d;584a81be8fddee4a8ac1cf59;584a81be8fddee4a8ac1cda3;PurchOrderLine;1.81|11|584a81be8fddee4a8ac1cf58|T +584a81be8fddee4a8ac1cfbf;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cdbf;PurchOrderLine;8.37|69|584a81be8fddee4a8ac1cfba|T +584a81be8fddee4a8ac1d294;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1cdb6;PurchOrderLine;5.05|21|584a81be8fddee4a8ac1d28f|T +584a81be8fddee4a8ac1d0db;584a81be8fddee4a8ac1d0d7;584a81be8fddee4a8ac1cdb7;PurchOrderLine;1.99|30|584a81be8fddee4a8ac1d0d6|T +584a81be8fddee4a8ac1d63a;584a81be8fddee4a8ac1d636;584a81be8fddee4a8ac1cdb5;PurchOrderLine;8.08|45|584a81be8fddee4a8ac1d635|T +584a81be8fddee4a8ac1cf47;584a81be8fddee4a8ac1cf43;584a81be8fddee4a8ac1cda3;PurchOrderLine;1.74|7|584a81be8fddee4a8ac1cf42|T +584a81be8fddee4a8ac1d72a;584a81be8fddee4a8ac1d726;584a81be8fddee4a8ac1cdb8;PurchOrderLine;0.78|34|584a81be8fddee4a8ac1d725|T +584a81be8fddee4a8ac1d3ce;584a81be8fddee4a8ac1d3ca;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|2|584a81be8fddee4a8ac1d3c9|T +584a81be8fddee4a8ac1d624;584a81be8fddee4a8ac1d620;584a81be8fddee4a8ac1cdca;PurchOrderLine;5.68|59|584a81be8fddee4a8ac1d61f|T +584a81be8fddee4a8ac1d193;584a81be8fddee4a8ac1d18f;584a81be8fddee4a8ac1cdca;PurchOrderLine;5.68|68|584a81be8fddee4a8ac1d18e|T +584a81be8fddee4a8ac1d0c0;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1cdc2;PurchOrderLine;5.17|89|584a81be8fddee4a8ac1d0bb|T +584a81be8fddee4a8ac1d52f;584a81be8fddee4a8ac1d52b;584a81be8fddee4a8ac1cdb5;PurchOrderLine;7.92|43|584a81be8fddee4a8ac1d52a|T +584a81be8fddee4a8ac1cf16;584a81be8fddee4a8ac1cf12;584a81be8fddee4a8ac1cd9b;PurchOrderLine;2.2|63|584a81be8fddee4a8ac1cf11|T +584a81be8fddee4a8ac1d327;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1cdc5;PurchOrderLine;6.6|62|584a81be8fddee4a8ac1d322|T +584a81be8fddee4a8ac1cfd5;584a81be8fddee4a8ac1cfd1;584a81be8fddee4a8ac1cda6;PurchOrderLine;8.08|97|584a81be8fddee4a8ac1cfd0|T +584a81be8fddee4a8ac1d378;584a81be8fddee4a8ac1d374;584a81be8fddee4a8ac1cdb6;PurchOrderLine;4.85|76|584a81be8fddee4a8ac1d373|T +584a81be8fddee4a8ac1d519;584a81be8fddee4a8ac1d515;584a81be8fddee4a8ac1cdbf;PurchOrderLine;8.7|46|584a81be8fddee4a8ac1d514|T +584a81be8fddee4a8ac1d248;584a81be8fddee4a8ac1d244;584a81be8fddee4a8ac1cda3;PurchOrderLine;1.7|100|584a81be8fddee4a8ac1d243|T +584a81be8fddee4a8ac1d714;584a81be8fddee4a8ac1d710;584a81be8fddee4a8ac1cda4;PurchOrderLine;9.01|84|584a81be8fddee4a8ac1d70f|T +584a81be8fddee4a8ac1d25e;584a81be8fddee4a8ac1d25a;584a81be8fddee4a8ac1cda8;PurchOrderLine;2.2|14|584a81be8fddee4a8ac1d259|T +584a81be8fddee4a8ac1d206;584a81be8fddee4a8ac1d202;584a81be8fddee4a8ac1cdaf;PurchOrderLine;6.97|82|584a81be8fddee4a8ac1d201|T +584a81be8fddee4a8ac1d7df;584a81be8fddee4a8ac1d7db;584a81be8fddee4a8ac1cdb7;PurchOrderLine;1.95|39|584a81be8fddee4a8ac1d7da|T +584a81be8fddee4a8ac1d21c;584a81be8fddee4a8ac1d218;584a81be8fddee4a8ac1cdae;PurchOrderLine;7.47|93|584a81be8fddee4a8ac1d217|T +584a81be8fddee4a8ac1d503;584a81be8fddee4a8ac1d4ff;584a81be8fddee4a8ac1cda1;PurchOrderLine;8.93|74|584a81be8fddee4a8ac1d4fe|T +584a81be8fddee4a8ac1d294;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1cdb6;PurchOrderLine;5.05|21|584a81be8fddee4a8ac1d28f|T +584a81be8fddee4a8ac1d127;584a81be8fddee4a8ac1d123;584a81be8fddee4a8ac1cd97;PurchOrderLine;4.66|49|584a81be8fddee4a8ac1d122|T +584a81be8fddee4a8ac1d60e;584a81be8fddee4a8ac1d60a;584a81be8fddee4a8ac1cdac;PurchOrderLine;1.66|72|584a81be8fddee4a8ac1d609|T +584a81be8fddee4a8ac1d0a5;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1cda9;PurchOrderLine;1.53|67|584a81be8fddee4a8ac1d0a0|T +584a81be8fddee4a8ac1d4ed;584a81be8fddee4a8ac1d4e9;584a81be8fddee4a8ac1cdbd;PurchOrderLine;0.77|81|584a81be8fddee4a8ac1d4e8|T +584a81be8fddee4a8ac1d032;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1cdb1;PurchOrderLine;7.59|90|584a81be8fddee4a8ac1d02d|T +584a81be8fddee4a8ac1d609;584a81be8fddee4a8ac1d605;584a81be8fddee4a8ac1cdac;SalesOrderLine;584a81be8fddee4a8ac1d60e|72|1.8|T +584a81be8fddee4a8ac1d398;584a81be8fddee4a8ac1d394;584a81be8fddee4a8ac1cd99;SalesOrderLine;584a81be8fddee4a8ac1d39d|9|7.57|T +584a81be8fddee4a8ac1d70f;584a81be8fddee4a8ac1d70b;584a81be8fddee4a8ac1cda4;SalesOrderLine;584a81be8fddee4a8ac1d714|84|9.19|T +584a81be8fddee4a8ac1d2bb;584a81be8fddee4a8ac1d2b7;584a81be8fddee4a8ac1cdc1;SalesOrderLine;584a81be8fddee4a8ac1d2c0|59|0.81|T +584a81be8fddee4a8ac1d725;584a81be8fddee4a8ac1d721;584a81be8fddee4a8ac1cdb8;SalesOrderLine;584a81be8fddee4a8ac1d72a|34|0.83|T +584a81be8fddee4a8ac1d0a0;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1cda9;SalesOrderLine;584a81be8fddee4a8ac1d0a5|67|1.5|T +584a81be8fddee4a8ac1cfe6;584a81be8fddee4a8ac1cfe2;584a81be8fddee4a8ac1cda3;SalesOrderLine;584a81be8fddee4a8ac1cfeb|17|1.84|T +584a81be8fddee4a8ac1d68d;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1cdb3;SalesOrderLine;584a81be8fddee4a8ac1d692|25|7.54|T +584a81be8fddee4a8ac1cf58;584a81be8fddee4a8ac1cf54;584a81be8fddee4a8ac1cda3;SalesOrderLine;584a81be8fddee4a8ac1cf5d|11|1.84|T +584a81be8fddee4a8ac1d3b3;584a81be8fddee4a8ac1d3af;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d3b8|49|5.24|T +584a81be8fddee4a8ac1d4be;584a81be8fddee4a8ac1d4ba;584a81be8fddee4a8ac1cda8;SalesOrderLine;584a81be8fddee4a8ac1d4c3|61|2.42|T +584a81be8fddee4a8ac1cffc;584a81be8fddee4a8ac1cff8;584a81be8fddee4a8ac1cdaf;SalesOrderLine;584a81be8fddee4a8ac1d001|75|7.39|T +584a81be8fddee4a8ac1d08a;584a81be8fddee4a8ac1d086;584a81be8fddee4a8ac1cdc4;SalesOrderLine;584a81be8fddee4a8ac1d08f|26|9.91|T +584a81be8fddee4a8ac1d463;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1cdc6;SalesOrderLine;584a81be8fddee4a8ac1d468|95|0.62|T +584a81be8fddee4a8ac1d138;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1cdb2;SalesOrderLine;584a81be8fddee4a8ac1d13d|40|3.11|T +584a81be8fddee4a8ac1d798;584a81be8fddee4a8ac1d794;584a81be8fddee4a8ac1cd9c;SalesOrderLine;584a81be8fddee4a8ac1d79d|88|9.57|T +584a81be8fddee4a8ac1cecf;584a81be8fddee4a8ac1cecb;584a81be8fddee4a8ac1cdaa;SalesOrderLine;584a81be8fddee4a8ac1ced4|11|0.81|T +584a81be8fddee4a8ac1d138;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1cdb2;SalesOrderLine;584a81be8fddee4a8ac1d13d|40|3.11|T +584a81be8fddee4a8ac1d499;584a81be8fddee4a8ac1d495;584a81be8fddee4a8ac1cda7;SalesOrderLine;584a81be8fddee4a8ac1d49e|51|6.51|T +584a81be8fddee4a8ac1d677;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1d67c|15|8.08|T +584a81be8fddee4a8ac1d3c9;584a81be8fddee4a8ac1d3c5;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d3ce|2|6.47|T +584a81be8fddee4a8ac1d012;584a81be8fddee4a8ac1d00e;584a81be8fddee4a8ac1cdc3;SalesOrderLine;584a81be8fddee4a8ac1d017|41|3.59|T +584a81be8fddee4a8ac1d0bb;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1cdc2;SalesOrderLine;584a81be8fddee4a8ac1d0c0|89|5.17|T +584a81be8fddee4a8ac1d483;584a81be8fddee4a8ac1d47f;584a81be8fddee4a8ac1cda0;SalesOrderLine;584a81be8fddee4a8ac1d488|62|9.12|T +584a81be8fddee4a8ac1d201;584a81be8fddee4a8ac1d1fd;584a81be8fddee4a8ac1cdaf;SalesOrderLine;584a81be8fddee4a8ac1d206|82|7.25|T +584a81be8fddee4a8ac1cf11;584a81be8fddee4a8ac1cf0d;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1cf16|63|2.52|T +584a81be8fddee4a8ac1d02d;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1cdb1;SalesOrderLine;584a81be8fddee4a8ac1d032|90|7.89|T +584a81be8fddee4a8ac1d556;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1cda8;SalesOrderLine;584a81be8fddee4a8ac1d55b|26|2.42|T +584a81be8fddee4a8ac1d756;584a81be8fddee4a8ac1d752;584a81be8fddee4a8ac1cda8;SalesOrderLine;584a81be8fddee4a8ac1d75b|51|2.46|T +584a81be8fddee4a8ac1d3df;584a81be8fddee4a8ac1d3db;584a81be8fddee4a8ac1cda0;SalesOrderLine;584a81be8fddee4a8ac1d3e4|46|9.29|T +584a81be8fddee4a8ac1d463;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1cdc6;SalesOrderLine;584a81be8fddee4a8ac1d468|95|0.62|T +584a81be8fddee4a8ac1cee5;584a81be8fddee4a8ac1cee1;584a81be8fddee4a8ac1cdc8;SalesOrderLine;584a81be8fddee4a8ac1ceea|80|4.17|T +584a81be8fddee4a8ac1cf89;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1cf8e|15|2.47|T +584a81be8fddee4a8ac1d661;584a81be8fddee4a8ac1d65d;584a81be8fddee4a8ac1cdbf;SalesOrderLine;584a81be8fddee4a8ac1d666|72|8.7|T +584a81be8fddee4a8ac1d043;584a81be8fddee4a8ac1d03f;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d048|77|5.44|T +584a81be8fddee4a8ac1d44d;584a81be8fddee4a8ac1d449;584a81be8fddee4a8ac1cd97;SalesOrderLine;584a81be8fddee4a8ac1d452|64|4.84|T +584a81be8fddee4a8ac1d6f4;584a81be8fddee4a8ac1d6f0;584a81be8fddee4a8ac1cda7;SalesOrderLine;584a81be8fddee4a8ac1d6f9|40|7.04|T +584a81be8fddee4a8ac1d22d;584a81be8fddee4a8ac1d229;584a81be8fddee4a8ac1cd98;SalesOrderLine;584a81be8fddee4a8ac1d232|66|4.99|T +584a81be8fddee4a8ac1d28f;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d294|21|5.15|T +584a81be8fddee4a8ac1d074;584a81be8fddee4a8ac1d070;584a81be8fddee4a8ac1cdb8;SalesOrderLine;584a81be8fddee4a8ac1d079|27|0.81|T +584a81be8fddee4a8ac1d437;584a81be8fddee4a8ac1d433;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d43c|68|6.73|T +584a81be8fddee4a8ac1d6c8;584a81be8fddee4a8ac1d6c4;584a81be8fddee4a8ac1cdc8;SalesOrderLine;584a81be8fddee4a8ac1d6cd|69|4.1|T +584a81be8fddee4a8ac1d64b;584a81be8fddee4a8ac1d647;584a81be8fddee4a8ac1cdcb;SalesOrderLine;584a81be8fddee4a8ac1d650|48|7.49|T +584a81be8fddee4a8ac1d3f5;584a81be8fddee4a8ac1d3f1;584a81be8fddee4a8ac1cd9d;SalesOrderLine;584a81be8fddee4a8ac1d3fa|54|2.98|T +584a81be8fddee4a8ac1d05e;584a81be8fddee4a8ac1d05a;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1d063|21|2.43|T +584a81be8fddee4a8ac1d421;584a81be8fddee4a8ac1d41d;584a81be8fddee4a8ac1cd98;SalesOrderLine;584a81be8fddee4a8ac1d426|12|5.18|T +584a81be8fddee4a8ac1d7ae;584a81be8fddee4a8ac1d7aa;584a81be8fddee4a8ac1cdb8;SalesOrderLine;584a81be8fddee4a8ac1d7b3|34|0.81|T +584a81be8fddee4a8ac1d40b;584a81be8fddee4a8ac1d407;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1d410|87|2.52|T +584a81be8fddee4a8ac1d2d1;584a81be8fddee4a8ac1d2cd;584a81be8fddee4a8ac1cda9;SalesOrderLine;584a81be8fddee4a8ac1d2d6|11|1.59|T +584a81be8fddee4a8ac1d1d5;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1cdb1;SalesOrderLine;584a81be8fddee4a8ac1d1da|54|7.89|T +584a81be8fddee4a8ac1d1a9;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1cd98;SalesOrderLine;584a81be8fddee4a8ac1d1ae|13|4.99|T +584a81be8fddee4a8ac1d635;584a81be8fddee4a8ac1d631;584a81be8fddee4a8ac1cdb5;SalesOrderLine;584a81be8fddee4a8ac1d63a|45|8.72|T +584a81be8fddee4a8ac1d122;584a81be8fddee4a8ac1d11e;584a81be8fddee4a8ac1cd97;SalesOrderLine;584a81be8fddee4a8ac1d127|49|4.84|T +584a81be8fddee4a8ac1d1eb;584a81be8fddee4a8ac1d1e7;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1d1f0|59|8.4|T +584a81be8fddee4a8ac1d7c4;584a81be8fddee4a8ac1d7c0;584a81be8fddee4a8ac1cdb3;SalesOrderLine;584a81be8fddee4a8ac1d7c9|49|7.84|T +584a81be8fddee4a8ac1d61f;584a81be8fddee4a8ac1d61b;584a81be8fddee4a8ac1cdca;SalesOrderLine;584a81be8fddee4a8ac1d624|59|6.01|T +584a81be8fddee4a8ac1d2e7;584a81be8fddee4a8ac1d2e3;584a81be8fddee4a8ac1cdc7;SalesOrderLine;584a81be8fddee4a8ac1d2ec|43|4.32|T +584a81be8fddee4a8ac1d7da;584a81be8fddee4a8ac1d7d6;584a81be8fddee4a8ac1cdb7;SalesOrderLine;584a81be8fddee4a8ac1d7df|39|2.14|T +584a81be8fddee4a8ac1d68d;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1cdb3;SalesOrderLine;584a81be8fddee4a8ac1d692|25|7.54|T +584a81be8fddee4a8ac1cfba;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cdbf;SalesOrderLine;584a81be8fddee4a8ac1cfbf|69|8.37|T +584a81be8fddee4a8ac1d5f3;584a81be8fddee4a8ac1d5ef;584a81be8fddee4a8ac1cd97;SalesOrderLine;584a81be8fddee4a8ac1d5f8|100|5.02|T +584a81be8fddee4a8ac1d1bf;584a81be8fddee4a8ac1d1bb;584a81be8fddee4a8ac1cdad;SalesOrderLine;584a81be8fddee4a8ac1d1c4|11|1.37|T +584a81be8fddee4a8ac1d162;584a81be8fddee4a8ac1d15e;584a81be8fddee4a8ac1cdba;SalesOrderLine;584a81be8fddee4a8ac1d167|61|4.45|T +584a81be8fddee4a8ac1d7f5;584a81be8fddee4a8ac1d7f1;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1d7fa|99|8.56|T +584a81be8fddee4a8ac1d5dd;584a81be8fddee4a8ac1d5d9;584a81be8fddee4a8ac1cdc2;SalesOrderLine;584a81be8fddee4a8ac1d5e2|97|5.37|T +584a81be8fddee4a8ac1d279;584a81be8fddee4a8ac1d275;584a81be8fddee4a8ac1cdcb;SalesOrderLine;584a81be8fddee4a8ac1d27e|42|7.49|T +584a81be8fddee4a8ac1d102;584a81be8fddee4a8ac1d0fe;584a81be8fddee4a8ac1cd97;SalesOrderLine;584a81be8fddee4a8ac1d107|52|4.93|T +584a81be8fddee4a8ac1d307;584a81be8fddee4a8ac1d303;584a81be8fddee4a8ac1cda9;SalesOrderLine;584a81be8fddee4a8ac1d30c|88|1.48|T +584a81be8fddee4a8ac1d5c2;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d5c7|85|6.73|T +584a81be8fddee4a8ac1d73b;584a81be8fddee4a8ac1d737;584a81be8fddee4a8ac1cdbd;SalesOrderLine;584a81be8fddee4a8ac1d740|35|0.8|T +584a81be8fddee4a8ac1d1d5;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1cdb1;SalesOrderLine;584a81be8fddee4a8ac1d1da|54|7.89|T +584a81be8fddee4a8ac1d0ec;584a81be8fddee4a8ac1d0e8;584a81be8fddee4a8ac1cda4;SalesOrderLine;584a81be8fddee4a8ac1d0f1|28|9.19|T +584a81be8fddee4a8ac1d243;584a81be8fddee4a8ac1d23f;584a81be8fddee4a8ac1cda3;SalesOrderLine;584a81be8fddee4a8ac1d248|100|1.84|T +584a81be8fddee4a8ac1cf27;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cdb9;SalesOrderLine;584a81be8fddee4a8ac1cf2c|81|7.47|T +584a81be8fddee4a8ac1d18e;584a81be8fddee4a8ac1d18a;584a81be8fddee4a8ac1cdca;SalesOrderLine;584a81be8fddee4a8ac1d193|68|6.12|T +584a81be8fddee4a8ac1d6de;584a81be8fddee4a8ac1d6da;584a81be8fddee4a8ac1cdba;SalesOrderLine;584a81be8fddee4a8ac1d6e3|66|4.28|T +584a81be8fddee4a8ac1cf6e;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cdbc;SalesOrderLine;584a81be8fddee4a8ac1cf73|83|7.5|T +584a81be8fddee4a8ac1d259;584a81be8fddee4a8ac1d255;584a81be8fddee4a8ac1cda8;SalesOrderLine;584a81be8fddee4a8ac1d25e|14|2.38|T +584a81be8fddee4a8ac1d02d;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1cdb1;SalesOrderLine;584a81be8fddee4a8ac1d032|90|7.89|T +584a81be8fddee4a8ac1d59d;584a81be8fddee4a8ac1d599;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d5a2|57|5.34|T +584a81be8fddee4a8ac1d178;584a81be8fddee4a8ac1d174;584a81be8fddee4a8ac1cdac;SalesOrderLine;584a81be8fddee4a8ac1d17d|51|1.76|T +584a81be8fddee4a8ac1d677;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1d67c|15|8.08|T +584a81be8fddee4a8ac1d6a8;584a81be8fddee4a8ac1d6a4;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1d6ad|20|2.43|T +584a81be8fddee4a8ac1d322;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d327|62|6.73|T +584a81be8fddee4a8ac1d587;584a81be8fddee4a8ac1d583;584a81be8fddee4a8ac1cdcb;SalesOrderLine;584a81be8fddee4a8ac1d58c|4|7.21|T +584a81be8fddee4a8ac1d76c;584a81be8fddee4a8ac1d768;584a81be8fddee4a8ac1cdc8;SalesOrderLine;584a81be8fddee4a8ac1d771|84|4.02|T +584a81be8fddee4a8ac1cf89;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cd9b;SalesOrderLine;584a81be8fddee4a8ac1cf8e|15|2.47|T +584a81be8fddee4a8ac1cf6e;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cdbc;SalesOrderLine;584a81be8fddee4a8ac1cf73|83|7.5|T +584a81be8fddee4a8ac1ce9e;584a81be8fddee4a8ac1ce9a;584a81be8fddee4a8ac1cdc3;SalesOrderLine;584a81be8fddee4a8ac1cea3|5|3.66|T +584a81be8fddee4a8ac1cefb;584a81be8fddee4a8ac1cef7;584a81be8fddee4a8ac1cdb1;SalesOrderLine;584a81be8fddee4a8ac1cf00|13|7.89|T +584a81be8fddee4a8ac1d322;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d327|62|6.73|T +584a81be8fddee4a8ac1d338;584a81be8fddee4a8ac1d334;584a81be8fddee4a8ac1cd9d;SalesOrderLine;584a81be8fddee4a8ac1d33d|88|3.03|T +584a81be8fddee4a8ac1cf9f;584a81be8fddee4a8ac1cf9b;584a81be8fddee4a8ac1cdbc;SalesOrderLine;584a81be8fddee4a8ac1cfa4|7|7.36|T +584a81be8fddee4a8ac1d571;584a81be8fddee4a8ac1d56d;584a81be8fddee4a8ac1cdb7;SalesOrderLine;584a81be8fddee4a8ac1d576|12|2.14|T +584a81be8fddee4a8ac1d28f;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d294|21|5.15|T +584a81be8fddee4a8ac1d556;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1cda8;SalesOrderLine;584a81be8fddee4a8ac1d55b|26|2.42|T +584a81be8fddee4a8ac1d0d6;584a81be8fddee4a8ac1d0d2;584a81be8fddee4a8ac1cdb7;SalesOrderLine;584a81be8fddee4a8ac1d0db|30|1.99|T +584a81be8fddee4a8ac1d353;584a81be8fddee4a8ac1d34f;584a81be8fddee4a8ac1cd9a;SalesOrderLine;584a81be8fddee4a8ac1d358|4|7.63|T +584a81be8fddee4a8ac1d217;584a81be8fddee4a8ac1d213;584a81be8fddee4a8ac1cdae;SalesOrderLine;584a81be8fddee4a8ac1d21c|93|7.92|T +584a81be8fddee4a8ac1cf27;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cdb9;SalesOrderLine;584a81be8fddee4a8ac1cf2c|81|7.47|T +584a81be8fddee4a8ac1d540;584a81be8fddee4a8ac1d53c;584a81be8fddee4a8ac1cdba;SalesOrderLine;584a81be8fddee4a8ac1d545|100|4.45|T +584a81be8fddee4a8ac1d52a;584a81be8fddee4a8ac1d526;584a81be8fddee4a8ac1cdb5;SalesOrderLine;584a81be8fddee4a8ac1d52f|43|8.56|T +584a81be8fddee4a8ac1d1a9;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1cd98;SalesOrderLine;584a81be8fddee4a8ac1d1ae|13|4.99|T +584a81be8fddee4a8ac1d373;584a81be8fddee4a8ac1d36f;584a81be8fddee4a8ac1cdb6;SalesOrderLine;584a81be8fddee4a8ac1d378|76|5.44|T +584a81be8fddee4a8ac1cfba;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cdbf;SalesOrderLine;584a81be8fddee4a8ac1cfbf|69|8.37|T +584a81be8fddee4a8ac1cf42;584a81be8fddee4a8ac1cf3e;584a81be8fddee4a8ac1cda3;SalesOrderLine;584a81be8fddee4a8ac1cf47|7|1.74|T +584a81be8fddee4a8ac1d5c2;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1cdc5;SalesOrderLine;584a81be8fddee4a8ac1d5c7|85|6.73|T +584a81be8fddee4a8ac1d514;584a81be8fddee4a8ac1d510;584a81be8fddee4a8ac1cdbf;SalesOrderLine;584a81be8fddee4a8ac1d519|46|8.7|T +584a81be8fddee4a8ac1d782;584a81be8fddee4a8ac1d77e;584a81be8fddee4a8ac1cdc6;SalesOrderLine;584a81be8fddee4a8ac1d787|72|0.62|T +584a81be8fddee4a8ac1d0a0;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1cda9;SalesOrderLine;584a81be8fddee4a8ac1d0a5|67|1.5|T +584a81be8fddee4a8ac1d0bb;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1cdc2;SalesOrderLine;584a81be8fddee4a8ac1d0c0|89|5.17|T +584a81be8fddee4a8ac1d4fe;584a81be8fddee4a8ac1d4fa;584a81be8fddee4a8ac1cda1;SalesOrderLine;584a81be8fddee4a8ac1d503|74|9.1|T +584a81be8fddee4a8ac1ceb4;584a81be8fddee4a8ac1ceb0;584a81be8fddee4a8ac1cdc1;SalesOrderLine;584a81be8fddee4a8ac1ceb9|88|0.82|T +584a81be8fddee4a8ac1d4e8;584a81be8fddee4a8ac1d4e4;584a81be8fddee4a8ac1cdbd;SalesOrderLine;584a81be8fddee4a8ac1d4ed|81|0.83|T +584a81be8fddee4a8ac1cfd0;584a81be8fddee4a8ac1cfcc;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1cfd5|97|8.72|T +584a81be8fddee4a8ac1d2a5;584a81be8fddee4a8ac1d2a1;584a81be8fddee4a8ac1cda6;SalesOrderLine;584a81be8fddee4a8ac1d2aa|35|8.4|T +584a81be8fddee4a8ac1d4af;584a81be8fddee4a8ac1d4ac;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||99|2.03|T +584a81be8fddee4a8ac1ceca;584a81be8fddee4a8ac1cec7;584a81be8fddee4a8ac1cdaa;SalesQuotationLine;0.76||11|0.81|T +584a81be8fddee4a8ac1d767;584a81be8fddee4a8ac1d764;584a81be8fddee4a8ac1cdc8;SalesQuotationLine;3.9||84|4.02|T +584a81be8fddee4a8ac1d189;584a81be8fddee4a8ac1d186;584a81be8fddee4a8ac1cdca;SalesQuotationLine;5.51||68|6.12|T +584a81be8fddee4a8ac1d212;584a81be8fddee4a8ac1d20f;584a81be8fddee4a8ac1cdae;SalesQuotationLine;7.4||93|7.92|T +584a81be8fddee4a8ac1d19f;584a81be8fddee4a8ac1d19c;584a81be8fddee4a8ac1cd9d;SalesQuotationLine;2.89||69|3.03|T +584a81be8fddee4a8ac1d1fc;584a81be8fddee4a8ac1d1f9;584a81be8fddee4a8ac1cdaf;SalesQuotationLine;7.04||82|7.25|T +584a81be8fddee4a8ac1d1e6;584a81be8fddee4a8ac1d1e3;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|59|8.4|T +584a81be8fddee4a8ac1d1d0;584a81be8fddee4a8ac1d1cd;584a81be8fddee4a8ac1cdb1;SalesQuotationLine;7.37||54|7.89|T +584a81be8fddee4a8ac1d1a4;584a81be8fddee4a8ac1d1a1;584a81be8fddee4a8ac1cd98;SalesQuotationLine;4.75||13|4.99|T +584a81be8fddee4a8ac1d6c3;584a81be8fddee4a8ac1d6c0;584a81be8fddee4a8ac1cdc8;SalesQuotationLine;3.9||69|4.1|T +584a81be8fddee4a8ac1d1ba;584a81be8fddee4a8ac1d1b7;584a81be8fddee4a8ac1cdad;SalesQuotationLine;1.3||11|1.37|T +584a81be8fddee4a8ac1d6be;584a81be8fddee4a8ac1d6bb;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||100|5.15|T +584a81be8fddee4a8ac1d6b9;584a81be8fddee4a8ac1d6b6;584a81be8fddee4a8ac1cdc6;SalesQuotationLine;0.6||73|0.61|T +584a81be8fddee4a8ac1d77d;584a81be8fddee4a8ac1d77a;584a81be8fddee4a8ac1cdc6;SalesQuotationLine;0.6||72|0.62|T +584a81be8fddee4a8ac1d6a3;584a81be8fddee4a8ac1d6a0;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||20|2.43|T +584a81be8fddee4a8ac1d69e;584a81be8fddee4a8ac1d69b;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||50|0.8|T +584a81be8fddee4a8ac1d688;584a81be8fddee4a8ac1d685;584a81be8fddee4a8ac1cdb3;SalesQuotationLine;7.47||25|7.54|T +584a81be8fddee4a8ac1d793;584a81be8fddee4a8ac1d790;584a81be8fddee4a8ac1cd9c;SalesQuotationLine;8.94||88|9.57|T +584a81be8fddee4a8ac1d672;584a81be8fddee4a8ac1d66f;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|15|8.08|T +584a81be8fddee4a8ac1d65c;584a81be8fddee4a8ac1d659;584a81be8fddee4a8ac1cdbf;SalesQuotationLine;8.29||72|8.7|T +584a81be8fddee4a8ac1d7a9;584a81be8fddee4a8ac1d7a6;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||34|0.81|T +584a81be8fddee4a8ac1d646;584a81be8fddee4a8ac1d643;584a81be8fddee4a8ac1cdcb;SalesQuotationLine;6.87||48|7.49|T +584a81be8fddee4a8ac1d630;584a81be8fddee4a8ac1d62d;584a81be8fddee4a8ac1cdb5;SalesQuotationLine;|8|45|8.72|T +584a81be8fddee4a8ac1d7bf;584a81be8fddee4a8ac1d7bc;584a81be8fddee4a8ac1cdb3;SalesQuotationLine;7.47||49|7.84|T +584a81be8fddee4a8ac1d70a;584a81be8fddee4a8ac1d707;584a81be8fddee4a8ac1cda4;SalesQuotationLine;8.92||84|9.19|T +584a81be8fddee4a8ac1cf3d;584a81be8fddee4a8ac1cf3a;584a81be8fddee4a8ac1cda3;SalesQuotationLine;1.72||7|1.74|T +584a81be8fddee4a8ac1d61a;584a81be8fddee4a8ac1d617;584a81be8fddee4a8ac1cdca;SalesQuotationLine;5.51||59|6.01|T +584a81be8fddee4a8ac1d7d5;584a81be8fddee4a8ac1d7d2;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||39|2.14|T +584a81be8fddee4a8ac1d736;584a81be8fddee4a8ac1d733;584a81be8fddee4a8ac1cdbd;SalesQuotationLine;0.76||35|0.8|T +584a81be8fddee4a8ac1d604;584a81be8fddee4a8ac1d601;584a81be8fddee4a8ac1cdac;SalesQuotationLine;1.68||72|1.8|T +584a81be8fddee4a8ac1d5ee;584a81be8fddee4a8ac1d5eb;584a81be8fddee4a8ac1cd97;SalesQuotationLine;4.52||100|5.02|T +584a81be8fddee4a8ac1d7eb;584a81be8fddee4a8ac1d7e8;584a81be8fddee4a8ac1cda0;SalesQuotationLine;8.85||93|8.94|T +584a81be8fddee4a8ac1d5d8;584a81be8fddee4a8ac1d5d5;584a81be8fddee4a8ac1cdc2;SalesQuotationLine;5.02||97|5.37|T +584a81be8fddee4a8ac1d5d3;584a81be8fddee4a8ac1d5d0;584a81be8fddee4a8ac1cdc4;SalesQuotationLine;9.26||68|9.54|T +584a81be8fddee4a8ac1d5bd;584a81be8fddee4a8ac1d5ba;584a81be8fddee4a8ac1cdc5;SalesQuotationLine;6.41||85|6.73|T +584a81be8fddee4a8ac1d7f0;584a81be8fddee4a8ac1d7ed;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|99|8.56|T +584a81be8fddee4a8ac1d806;584a81be8fddee4a8ac1d803;584a81be8fddee4a8ac1cd99;SalesQuotationLine;7.21||38|7.28|T +584a81be8fddee4a8ac1cf38;584a81be8fddee4a8ac1cf35;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||56|2.34|T +584a81be8fddee4a8ac1cf53;584a81be8fddee4a8ac1cf50;584a81be8fddee4a8ac1cda3;SalesQuotationLine;1.72||11|1.84|T +584a81be8fddee4a8ac1d5b8;584a81be8fddee4a8ac1d5b5;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||29|0.83|T +584a81be8fddee4a8ac1d5b3;584a81be8fddee4a8ac1d5b0;584a81be8fddee4a8ac1cdc3;SalesQuotationLine;3.42||17|3.59|T +584a81be8fddee4a8ac1cf69;584a81be8fddee4a8ac1cf66;584a81be8fddee4a8ac1cdbc;SalesQuotationLine;6.88||83|7.5|T +584a81be8fddee4a8ac1d5ae;584a81be8fddee4a8ac1d5ab;584a81be8fddee4a8ac1cdc2;SalesQuotationLine;5.02||82|5.17|T +584a81be8fddee4a8ac1cf22;584a81be8fddee4a8ac1cf1f;584a81be8fddee4a8ac1cdb9;SalesQuotationLine;7.11||81|7.47|T +584a81be8fddee4a8ac1d598;584a81be8fddee4a8ac1d595;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||57|5.34|T +584a81be8fddee4a8ac1cf7f;584a81be8fddee4a8ac1cf7c;584a81be8fddee4a8ac1cdba;SalesQuotationLine;4.16||22|4.2|T +584a81be8fddee4a8ac1d582;584a81be8fddee4a8ac1d57f;584a81be8fddee4a8ac1cdcb;SalesQuotationLine;6.87||4|7.21|T +584a81be8fddee4a8ac1d56c;584a81be8fddee4a8ac1d569;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||12|2.14|T +584a81be8fddee4a8ac1ce99;584a81be8fddee4a8ac1ce96;584a81be8fddee4a8ac1cdc3;SalesQuotationLine;3.42||5|3.66|T +584a81be8fddee4a8ac1cf84;584a81be8fddee4a8ac1cf81;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||15|2.47|T +584a81be8fddee4a8ac1d567;584a81be8fddee4a8ac1d564;584a81be8fddee4a8ac1cdba;SalesQuotationLine;4.16||47|4.2|T +584a81be8fddee4a8ac1cf9a;584a81be8fddee4a8ac1cf97;584a81be8fddee4a8ac1cdbc;SalesQuotationLine;6.88||7|7.36|T +584a81be8fddee4a8ac1d551;584a81be8fddee4a8ac1d54e;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||26|2.42|T +584a81be8fddee4a8ac1cfb0;584a81be8fddee4a8ac1cfad;584a81be8fddee4a8ac1cdb4;SalesQuotationLine;5.9||52|6.2|T +584a81be8fddee4a8ac1cfb5;584a81be8fddee4a8ac1cfb2;584a81be8fddee4a8ac1cdbf;SalesQuotationLine;8.29||69|8.37|T +584a81be8fddee4a8ac1d53b;584a81be8fddee4a8ac1d538;584a81be8fddee4a8ac1cdba;SalesQuotationLine;4.16||100|4.45|T +584a81be8fddee4a8ac1d525;584a81be8fddee4a8ac1d522;584a81be8fddee4a8ac1cdb5;SalesQuotationLine;|8|43|8.56|T +584a81be8fddee4a8ac1d50f;584a81be8fddee4a8ac1d50c;584a81be8fddee4a8ac1cdbf;SalesQuotationLine;8.29||46|8.7|T +584a81be8fddee4a8ac1cfcb;584a81be8fddee4a8ac1cfc8;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|97|8.72|T +584a81be8fddee4a8ac1d4f9;584a81be8fddee4a8ac1d4f6;584a81be8fddee4a8ac1cda1;SalesQuotationLine;8.67||74|9.1|T +584a81be8fddee4a8ac1d4e3;584a81be8fddee4a8ac1d4e0;584a81be8fddee4a8ac1cdbd;SalesQuotationLine;0.76||81|0.83|T +584a81be8fddee4a8ac1cfe1;584a81be8fddee4a8ac1cfde;584a81be8fddee4a8ac1cda3;SalesQuotationLine;1.72||17|1.84|T +584a81be8fddee4a8ac1d4de;584a81be8fddee4a8ac1d4db;584a81be8fddee4a8ac1cdad;SalesQuotationLine;1.3||81|1.34|T +584a81be8fddee4a8ac1d4d9;584a81be8fddee4a8ac1d4d6;584a81be8fddee4a8ac1cdad;SalesQuotationLine;1.3||23|1.39|T +584a81be8fddee4a8ac1cf0c;584a81be8fddee4a8ac1cf09;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||63|2.52|T +584a81be8fddee4a8ac1d4d4;584a81be8fddee4a8ac1d4d1;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||86|2.29|T +584a81be8fddee4a8ac1d4cf;584a81be8fddee4a8ac1d4cc;584a81be8fddee4a8ac1cdab;SalesQuotationLine;4.13||64|4.09|T +584a81be8fddee4a8ac1cff7;584a81be8fddee4a8ac1cff4;584a81be8fddee4a8ac1cdaf;SalesQuotationLine;7.04||75|7.39|T +584a81be8fddee4a8ac1d74c;584a81be8fddee4a8ac1d749;584a81be8fddee4a8ac1cda0;SalesQuotationLine;8.85||80|8.76|T +584a81be8fddee4a8ac1d4b9;584a81be8fddee4a8ac1d4b6;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||61|2.42|T +584a81be8fddee4a8ac1d4b4;584a81be8fddee4a8ac1d4b1;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||75|0.8|T +584a81be8fddee4a8ac1d4aa;584a81be8fddee4a8ac1d4a7;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|68|8.08|T +584a81be8fddee4a8ac1d705;584a81be8fddee4a8ac1d702;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||62|2.1|T +584a81be8fddee4a8ac1d494;584a81be8fddee4a8ac1d491;584a81be8fddee4a8ac1cda7;SalesQuotationLine;6.58||51|6.51|T +584a81be8fddee4a8ac1d00d;584a81be8fddee4a8ac1d00a;584a81be8fddee4a8ac1cdc3;SalesQuotationLine;3.42||41|3.59|T +584a81be8fddee4a8ac1d47e;584a81be8fddee4a8ac1d47b;584a81be8fddee4a8ac1cda0;SalesQuotationLine;8.85||62|9.12|T +584a81be8fddee4a8ac1d479;584a81be8fddee4a8ac1d476;584a81be8fddee4a8ac1cda5;SalesQuotationLine;8.3||66|8.55|T +584a81be8fddee4a8ac1d023;584a81be8fddee4a8ac1d020;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||17|5.24|T +584a81be8fddee4a8ac1d751;584a81be8fddee4a8ac1d74e;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||51|2.46|T +584a81be8fddee4a8ac1d474;584a81be8fddee4a8ac1d471;584a81be8fddee4a8ac1cdb1;SalesQuotationLine;7.37||89|7.59|T +584a81be8fddee4a8ac1d45e;584a81be8fddee4a8ac1d45b;584a81be8fddee4a8ac1cdc6;SalesQuotationLine;0.6||95|0.62|T +584a81be8fddee4a8ac1d028;584a81be8fddee4a8ac1d025;584a81be8fddee4a8ac1cdb1;SalesQuotationLine;7.37||90|7.89|T +584a81be8fddee4a8ac1d448;584a81be8fddee4a8ac1d445;584a81be8fddee4a8ac1cd97;SalesQuotationLine;4.52||64|4.84|T +584a81be8fddee4a8ac1d03e;584a81be8fddee4a8ac1d03b;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||77|5.44|T +584a81be8fddee4a8ac1d432;584a81be8fddee4a8ac1d42f;584a81be8fddee4a8ac1cdc5;SalesQuotationLine;6.41||68|6.73|T +584a81be8fddee4a8ac1d720;584a81be8fddee4a8ac1d71d;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||34|0.83|T +584a81be8fddee4a8ac1d054;584a81be8fddee4a8ac1d051;584a81be8fddee4a8ac1cda9;SalesQuotationLine;1.49||87|1.48|T +584a81be8fddee4a8ac1ce8a;584a81be8fddee4a8ac1ce87;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||6|2.38|T +584a81be8fddee4a8ac1d059;584a81be8fddee4a8ac1d056;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||21|2.43|T +584a81be8fddee4a8ac1d41c;584a81be8fddee4a8ac1d419;584a81be8fddee4a8ac1cd98;SalesQuotationLine;4.75||12|5.18|T +584a81be8fddee4a8ac1d406;584a81be8fddee4a8ac1d403;584a81be8fddee4a8ac1cd9b;SalesQuotationLine;2.27||87|2.52|T +584a81be8fddee4a8ac1d3f0;584a81be8fddee4a8ac1d3ed;584a81be8fddee4a8ac1cd9d;SalesQuotationLine;2.89||54|2.98|T +584a81be8fddee4a8ac1ce8f;584a81be8fddee4a8ac1ce8c;584a81be8fddee4a8ac1cda7;SalesQuotationLine;6.58||85|6.65|T +584a81be8fddee4a8ac1d06f;584a81be8fddee4a8ac1d06c;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||27|0.81|T +584a81be8fddee4a8ac1d3da;584a81be8fddee4a8ac1d3d7;584a81be8fddee4a8ac1cda0;SalesQuotationLine;8.85||46|9.29|T +584a81be8fddee4a8ac1d3c4;584a81be8fddee4a8ac1d3c1;584a81be8fddee4a8ac1cdc5;SalesQuotationLine;6.41||2|6.47|T +584a81be8fddee4a8ac1ceaf;584a81be8fddee4a8ac1ceac;584a81be8fddee4a8ac1cdc1;SalesQuotationLine;0.8||88|0.82|T +584a81be8fddee4a8ac1d085;584a81be8fddee4a8ac1d082;584a81be8fddee4a8ac1cdc4;SalesQuotationLine;9.26||26|9.91|T +584a81be8fddee4a8ac1d3ae;584a81be8fddee4a8ac1d3ab;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||49|5.24|T +584a81be8fddee4a8ac1d6ef;584a81be8fddee4a8ac1d6ec;584a81be8fddee4a8ac1cda7;SalesQuotationLine;6.58||40|7.04|T +584a81be8fddee4a8ac1d09b;584a81be8fddee4a8ac1d098;584a81be8fddee4a8ac1cda9;SalesQuotationLine;1.49||67|1.5|T +584a81be8fddee4a8ac1d3a9;584a81be8fddee4a8ac1d3a6;584a81be8fddee4a8ac1cdaa;SalesQuotationLine;0.76||73|0.8|T +584a81be8fddee4a8ac1d393;584a81be8fddee4a8ac1d390;584a81be8fddee4a8ac1cd99;SalesQuotationLine;7.21||9|7.57|T +584a81be8fddee4a8ac1d0b1;584a81be8fddee4a8ac1d0ae;584a81be8fddee4a8ac1cdab;SalesQuotationLine;4.13||65|4.17|T +584a81be8fddee4a8ac1d38e;584a81be8fddee4a8ac1d38b;584a81be8fddee4a8ac1cdb3;SalesQuotationLine;7.47||37|7.84|T +584a81be8fddee4a8ac1cef6;584a81be8fddee4a8ac1cef3;584a81be8fddee4a8ac1cdb1;SalesQuotationLine;7.37||13|7.89|T +584a81be8fddee4a8ac1d389;584a81be8fddee4a8ac1d386;584a81be8fddee4a8ac1cdb2;SalesQuotationLine;2.96||98|3.05|T +584a81be8fddee4a8ac1d384;584a81be8fddee4a8ac1d381;584a81be8fddee4a8ac1cdb2;SalesQuotationLine;2.96||2|3.11|T +584a81be8fddee4a8ac1d36e;584a81be8fddee4a8ac1d36b;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||76|5.44|T +584a81be8fddee4a8ac1d0b6;584a81be8fddee4a8ac1d0b3;584a81be8fddee4a8ac1cdc2;SalesQuotationLine;5.02||89|5.17|T +584a81be8fddee4a8ac1d369;584a81be8fddee4a8ac1d366;584a81be8fddee4a8ac1cdc4;SalesQuotationLine;9.26||23|9.54|T +584a81be8fddee4a8ac1d364;584a81be8fddee4a8ac1d361;584a81be8fddee4a8ac1cdbc;SalesQuotationLine;6.88||51|7.09|T +584a81be8fddee4a8ac1d0cc;584a81be8fddee4a8ac1d0c9;584a81be8fddee4a8ac1cd9f;SalesQuotationLine;5.14||36|5.4|T +584a81be8fddee4a8ac1d34e;584a81be8fddee4a8ac1d34b;584a81be8fddee4a8ac1cd9a;SalesQuotationLine;7.27||4|7.63|T +584a81be8fddee4a8ac1d0d1;584a81be8fddee4a8ac1d0ce;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||30|1.99|T +584a81be8fddee4a8ac1d349;584a81be8fddee4a8ac1d346;584a81be8fddee4a8ac1cda4;SalesQuotationLine;8.92||7|9.37|T +584a81be8fddee4a8ac1d333;584a81be8fddee4a8ac1d330;584a81be8fddee4a8ac1cd9d;SalesQuotationLine;2.89||88|3.03|T +584a81be8fddee4a8ac1d0e7;584a81be8fddee4a8ac1d0e4;584a81be8fddee4a8ac1cda4;SalesQuotationLine;8.92||28|9.19|T +584a81be8fddee4a8ac1d31d;584a81be8fddee4a8ac1d31a;584a81be8fddee4a8ac1cdc5;SalesQuotationLine;6.41||62|6.73|T +584a81be8fddee4a8ac1d318;584a81be8fddee4a8ac1d315;584a81be8fddee4a8ac1cdc2;SalesQuotationLine;5.02||8|5.07|T +584a81be8fddee4a8ac1d0fd;584a81be8fddee4a8ac1d0fa;584a81be8fddee4a8ac1cd97;SalesQuotationLine;4.52||52|4.93|T +584a81be8fddee4a8ac1d302;584a81be8fddee4a8ac1d2ff;584a81be8fddee4a8ac1cda9;SalesQuotationLine;1.49||88|1.48|T +584a81be8fddee4a8ac1d2fd;584a81be8fddee4a8ac1d2fa;584a81be8fddee4a8ac1cdb5;SalesQuotationLine;|8|3|8.56|T +584a81be8fddee4a8ac1cee0;584a81be8fddee4a8ac1cedd;584a81be8fddee4a8ac1cdc8;SalesQuotationLine;3.9||80|4.17|T +584a81be8fddee4a8ac1d2f8;584a81be8fddee4a8ac1d2f5;584a81be8fddee4a8ac1cdb7;SalesQuotationLine;1.93||44|1.99|T +584a81be8fddee4a8ac1d2e2;584a81be8fddee4a8ac1d2df;584a81be8fddee4a8ac1cdc7;SalesQuotationLine;4.19||43|4.32|T +584a81be8fddee4a8ac1d113;584a81be8fddee4a8ac1d110;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||99|0.78|T +584a81be8fddee4a8ac1d118;584a81be8fddee4a8ac1d115;584a81be8fddee4a8ac1cdc2;SalesQuotationLine;5.02||16|5.17|T +584a81be8fddee4a8ac1d6d9;584a81be8fddee4a8ac1d6d6;584a81be8fddee4a8ac1cdba;SalesQuotationLine;4.16||66|4.28|T +584a81be8fddee4a8ac1cec5;584a81be8fddee4a8ac1cec2;584a81be8fddee4a8ac1cda1;SalesQuotationLine;8.67||45|8.93|T +584a81be8fddee4a8ac1d11d;584a81be8fddee4a8ac1d11a;584a81be8fddee4a8ac1cd97;SalesQuotationLine;4.52||49|4.84|T +584a81be8fddee4a8ac1d2cc;584a81be8fddee4a8ac1d2c9;584a81be8fddee4a8ac1cda9;SalesQuotationLine;1.49||11|1.59|T +584a81be8fddee4a8ac1ce94;584a81be8fddee4a8ac1ce91;584a81be8fddee4a8ac1cdc7;SalesQuotationLine;4.19||14|4.15|T +584a81be8fddee4a8ac1d133;584a81be8fddee4a8ac1d130;584a81be8fddee4a8ac1cdb2;SalesQuotationLine;2.96||40|3.11|T +584a81be8fddee4a8ac1d2b6;584a81be8fddee4a8ac1d2b3;584a81be8fddee4a8ac1cdc1;SalesQuotationLine;0.8||59|0.81|T +584a81be8fddee4a8ac1d2a0;584a81be8fddee4a8ac1d29d;584a81be8fddee4a8ac1cda6;SalesQuotationLine;|8|35|8.4|T +584a81be8fddee4a8ac1d149;584a81be8fddee4a8ac1d146;584a81be8fddee4a8ac1cdb8;SalesQuotationLine;0.76||23|0.81|T +584a81be8fddee4a8ac1d28a;584a81be8fddee4a8ac1d287;584a81be8fddee4a8ac1cdb6;SalesQuotationLine;4.9||21|5.15|T +584a81be8fddee4a8ac1d14e;584a81be8fddee4a8ac1d14b;584a81be8fddee4a8ac1cda9;SalesQuotationLine;1.49||60|1.5|T +584a81be8fddee4a8ac1d153;584a81be8fddee4a8ac1d150;584a81be8fddee4a8ac1cd9a;SalesQuotationLine;7.27||33|7.63|T +584a81be8fddee4a8ac1d158;584a81be8fddee4a8ac1d155;584a81be8fddee4a8ac1cd9a;SalesQuotationLine;7.27||13|7.49|T +584a81be8fddee4a8ac1d15d;584a81be8fddee4a8ac1d15a;584a81be8fddee4a8ac1cdba;SalesQuotationLine;4.16||61|4.45|T +584a81be8fddee4a8ac1d274;584a81be8fddee4a8ac1d271;584a81be8fddee4a8ac1cdcb;SalesQuotationLine;6.87||42|7.49|T +584a81be8fddee4a8ac1d26f;584a81be8fddee4a8ac1d26c;584a81be8fddee4a8ac1cdb5;SalesQuotationLine;|8|88|8.4|T +584a81be8fddee4a8ac1d26a;584a81be8fddee4a8ac1d267;584a81be8fddee4a8ac1cdb5;SalesQuotationLine;|8|44|8.24|T +584a81be8fddee4a8ac1d254;584a81be8fddee4a8ac1d251;584a81be8fddee4a8ac1cda8;SalesQuotationLine;2.22||14|2.38|T +584a81be8fddee4a8ac1d173;584a81be8fddee4a8ac1d170;584a81be8fddee4a8ac1cdac;SalesQuotationLine;1.68||51|1.76|T +584a81be8fddee4a8ac1d23e;584a81be8fddee4a8ac1d23b;584a81be8fddee4a8ac1cda3;SalesQuotationLine;1.72||100|1.84|T +584a81be8fddee4a8ac1d228;584a81be8fddee4a8ac1d225;584a81be8fddee4a8ac1cd98;SalesQuotationLine;4.75||66|4.99|T +584a81be8fddee4a8ac1ee9e;584a81be8fddee4a8ac1ee8d;584a81be8fddee4a8ac1ee99;allocatedTo; +584a81be8fddee4a8ac1f02f;584a81be8fddee4a8ac1f019;584a81be8fddee4a8ac1f02d;allocatedTo; +584a81be8fddee4a8ac1e44f;584a81be8fddee4a8ac1e43d;584a81be8fddee4a8ac1e449;allocatedTo; +584a81be8fddee4a8ac1e8ca;584a81be8fddee4a8ac1e8c5;584a81be8fddee4a8ac1e8ac;allocatedTo; +584a81be8fddee4a8ac1ece9;584a81be8fddee4a8ac1ecd6;584a81be8fddee4a8ac1ece6;allocatedTo; +584a81be8fddee4a8ac1eb73;584a81be8fddee4a8ac1eb52;584a81be8fddee4a8ac1eb59;allocatedTo; +584a81be8fddee4a8ac1f649;584a81be8fddee4a8ac1f62a;584a81be8fddee4a8ac1f647;allocatedTo; +584a81be8fddee4a8ac1e820;584a81be8fddee4a8ac1e815;584a81be8fddee4a8ac1e81e;allocatedTo; +584a81be8fddee4a8ac1fd9f;584a81be8fddee4a8ac1fd96;584a81be8fddee4a8ac1fd9d;allocatedTo; +584a81be8fddee4a8ac1ebbc;584a81be8fddee4a8ac1ebb3;584a81be8fddee4a8ac1ebba;allocatedTo; +584a81be8fddee4a8ac1fc98;584a81be8fddee4a8ac1fc8e;584a81be8fddee4a8ac1fc96;allocatedTo; +584a81be8fddee4a8ac1e7c2;584a81be8fddee4a8ac1e7b3;584a81be8fddee4a8ac1e7c0;allocatedTo; +584a81be8fddee4a8ac1fde8;584a81be8fddee4a8ac1fde0;584a81be8fddee4a8ac1fde5;allocatedTo; +584a81be8fddee4a8ac1f388;584a81be8fddee4a8ac1f370;584a81be8fddee4a8ac1f386;allocatedTo; +584a81be8fddee4a8ac1e8b2;584a81be8fddee4a8ac1e8a6;584a81be8fddee4a8ac1e8b0;allocatedTo; +584a81be8fddee4a8ac1fbd3;584a81be8fddee4a8ac1fbc4;584a81be8fddee4a8ac1fbcf;allocatedTo; +584a81be8fddee4a8ac1edfc;584a81be8fddee4a8ac1ede6;584a81be8fddee4a8ac1edf9;allocatedTo; +584a81be8fddee4a8ac1ea43;584a81be8fddee4a8ac1ea2f;584a81be8fddee4a8ac1ea40;allocatedTo; +584a81be8fddee4a8ac1d372;584a81be8fddee4a8ac1d36f;584a81be8fddee4a8ac1d36b;basedOn; +584a81be8fddee4a8ac1d6f3;584a81be8fddee4a8ac1d6f0;584a81be8fddee4a8ac1d6ec;basedOn; +584a81be8fddee4a8ac1d513;584a81be8fddee4a8ac1d510;584a81be8fddee4a8ac1d50c;basedOn; +584a81be8fddee4a8ac1d529;584a81be8fddee4a8ac1d526;584a81be8fddee4a8ac1d522;basedOn; +584a81be8fddee4a8ac1d0ba;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1d0b3;basedOn; +584a81be8fddee4a8ac1cfb9;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cfb2;basedOn; +584a81be8fddee4a8ac1d200;584a81be8fddee4a8ac1d1fd;584a81be8fddee4a8ac1d1f9;basedOn; +584a81be8fddee4a8ac1d28e;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1d287;basedOn; +584a81be8fddee4a8ac1d177;584a81be8fddee4a8ac1d174;584a81be8fddee4a8ac1d170;basedOn; +584a81be8fddee4a8ac1d6a7;584a81be8fddee4a8ac1d6a4;584a81be8fddee4a8ac1d6a0;basedOn; +584a81be8fddee4a8ac1d53f;584a81be8fddee4a8ac1d53c;584a81be8fddee4a8ac1d538;basedOn; +584a81be8fddee4a8ac1d352;584a81be8fddee4a8ac1d34f;584a81be8fddee4a8ac1d34b;basedOn; +584a81be8fddee4a8ac1cf9e;584a81be8fddee4a8ac1cf9b;584a81be8fddee4a8ac1cf97;basedOn; +584a81be8fddee4a8ac1d73a;584a81be8fddee4a8ac1d737;584a81be8fddee4a8ac1d733;basedOn; +584a81be8fddee4a8ac1d0d5;584a81be8fddee4a8ac1d0d2;584a81be8fddee4a8ac1d0ce;basedOn; +584a81be8fddee4a8ac1d555;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1d54e;basedOn; +584a81be8fddee4a8ac1cf26;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cf1f;basedOn; +584a81be8fddee4a8ac1d70e;584a81be8fddee4a8ac1d70b;584a81be8fddee4a8ac1d707;basedOn; +584a81be8fddee4a8ac1d337;584a81be8fddee4a8ac1d334;584a81be8fddee4a8ac1d330;basedOn; +584a81be8fddee4a8ac1cf88;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cf81;basedOn; +584a81be8fddee4a8ac1d570;584a81be8fddee4a8ac1d56d;584a81be8fddee4a8ac1d569;basedOn; +584a81be8fddee4a8ac1d781;584a81be8fddee4a8ac1d77e;584a81be8fddee4a8ac1d77a;basedOn; +584a81be8fddee4a8ac1d0eb;584a81be8fddee4a8ac1d0e8;584a81be8fddee4a8ac1d0e4;basedOn; +584a81be8fddee4a8ac1d586;584a81be8fddee4a8ac1d583;584a81be8fddee4a8ac1d57f;basedOn; +584a81be8fddee4a8ac1d59c;584a81be8fddee4a8ac1d599;584a81be8fddee4a8ac1d595;basedOn; +584a81be8fddee4a8ac1d76b;584a81be8fddee4a8ac1d768;584a81be8fddee4a8ac1d764;basedOn; +584a81be8fddee4a8ac1d321;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1d31a;basedOn; +584a81be8fddee4a8ac1cf6d;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cf66;basedOn; +584a81be8fddee4a8ac1ce9d;584a81be8fddee4a8ac1ce9a;584a81be8fddee4a8ac1ce96;basedOn; +584a81be8fddee4a8ac1d6dd;584a81be8fddee4a8ac1d6da;584a81be8fddee4a8ac1d6d6;basedOn; +584a81be8fddee4a8ac1d7f4;584a81be8fddee4a8ac1d7f1;584a81be8fddee4a8ac1d7ed;basedOn; +584a81be8fddee4a8ac1d101;584a81be8fddee4a8ac1d0fe;584a81be8fddee4a8ac1d0fa;basedOn; +584a81be8fddee4a8ac1d161;584a81be8fddee4a8ac1d15e;584a81be8fddee4a8ac1d15a;basedOn; +584a81be8fddee4a8ac1d5c1;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1d5ba;basedOn; +584a81be8fddee4a8ac1d306;584a81be8fddee4a8ac1d303;584a81be8fddee4a8ac1d2ff;basedOn; +584a81be8fddee4a8ac1d278;584a81be8fddee4a8ac1d275;584a81be8fddee4a8ac1d271;basedOn; +584a81be8fddee4a8ac1d5dc;584a81be8fddee4a8ac1d5d9;584a81be8fddee4a8ac1d5d5;basedOn; +584a81be8fddee4a8ac1d6c7;584a81be8fddee4a8ac1d6c4;584a81be8fddee4a8ac1d6c0;basedOn; +584a81be8fddee4a8ac1d1be;584a81be8fddee4a8ac1d1bb;584a81be8fddee4a8ac1d1b7;basedOn; +584a81be8fddee4a8ac1d5f2;584a81be8fddee4a8ac1d5ef;584a81be8fddee4a8ac1d5eb;basedOn; +584a81be8fddee4a8ac1cece;584a81be8fddee4a8ac1cecb;584a81be8fddee4a8ac1cec7;basedOn; +584a81be8fddee4a8ac1cee4;584a81be8fddee4a8ac1cee1;584a81be8fddee4a8ac1cedd;basedOn; +584a81be8fddee4a8ac1d1d4;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1d1cd;basedOn; +584a81be8fddee4a8ac1d2e6;584a81be8fddee4a8ac1d2e3;584a81be8fddee4a8ac1d2df;basedOn; +584a81be8fddee4a8ac1d216;584a81be8fddee4a8ac1d213;584a81be8fddee4a8ac1d20f;basedOn; +584a81be8fddee4a8ac1d22c;584a81be8fddee4a8ac1d229;584a81be8fddee4a8ac1d225;basedOn; +584a81be8fddee4a8ac1d121;584a81be8fddee4a8ac1d11e;584a81be8fddee4a8ac1d11a;basedOn; +584a81be8fddee4a8ac1d7d9;584a81be8fddee4a8ac1d7d6;584a81be8fddee4a8ac1d7d2;basedOn; +584a81be8fddee4a8ac1d608;584a81be8fddee4a8ac1d605;584a81be8fddee4a8ac1d601;basedOn; +584a81be8fddee4a8ac1d258;584a81be8fddee4a8ac1d255;584a81be8fddee4a8ac1d251;basedOn; +584a81be8fddee4a8ac1d2d0;584a81be8fddee4a8ac1d2cd;584a81be8fddee4a8ac1d2c9;basedOn; +584a81be8fddee4a8ac1d1a8;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1d1a1;basedOn; +584a81be8fddee4a8ac1d61e;584a81be8fddee4a8ac1d61b;584a81be8fddee4a8ac1d617;basedOn; +584a81be8fddee4a8ac1cf41;584a81be8fddee4a8ac1cf3e;584a81be8fddee4a8ac1cf3a;basedOn; +584a81be8fddee4a8ac1d634;584a81be8fddee4a8ac1d631;584a81be8fddee4a8ac1d62d;basedOn; +584a81be8fddee4a8ac1d7c3;584a81be8fddee4a8ac1d7c0;584a81be8fddee4a8ac1d7bc;basedOn; +584a81be8fddee4a8ac1d40a;584a81be8fddee4a8ac1d407;584a81be8fddee4a8ac1d403;basedOn; +584a81be8fddee4a8ac1d3f4;584a81be8fddee4a8ac1d3f1;584a81be8fddee4a8ac1d3ed;basedOn; +584a81be8fddee4a8ac1d755;584a81be8fddee4a8ac1d752;584a81be8fddee4a8ac1d74e;basedOn; +584a81be8fddee4a8ac1d420;584a81be8fddee4a8ac1d41d;584a81be8fddee4a8ac1d419;basedOn; +584a81be8fddee4a8ac1d05d;584a81be8fddee4a8ac1d05a;584a81be8fddee4a8ac1d056;basedOn; +584a81be8fddee4a8ac1d073;584a81be8fddee4a8ac1d070;584a81be8fddee4a8ac1d06c;basedOn; +584a81be8fddee4a8ac1d242;584a81be8fddee4a8ac1d23f;584a81be8fddee4a8ac1d23b;basedOn; +584a81be8fddee4a8ac1d64a;584a81be8fddee4a8ac1d647;584a81be8fddee4a8ac1d643;basedOn; +584a81be8fddee4a8ac1ceb3;584a81be8fddee4a8ac1ceb0;584a81be8fddee4a8ac1ceac;basedOn; +584a81be8fddee4a8ac1cefa;584a81be8fddee4a8ac1cef7;584a81be8fddee4a8ac1cef3;basedOn; +584a81be8fddee4a8ac1d3de;584a81be8fddee4a8ac1d3db;584a81be8fddee4a8ac1d3d7;basedOn; +584a81be8fddee4a8ac1d042;584a81be8fddee4a8ac1d03f;584a81be8fddee4a8ac1d03b;basedOn; +584a81be8fddee4a8ac1d436;584a81be8fddee4a8ac1d433;584a81be8fddee4a8ac1d42f;basedOn; +584a81be8fddee4a8ac1d44c;584a81be8fddee4a8ac1d449;584a81be8fddee4a8ac1d445;basedOn; +584a81be8fddee4a8ac1d02c;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1d025;basedOn; +584a81be8fddee4a8ac1d7ad;584a81be8fddee4a8ac1d7aa;584a81be8fddee4a8ac1d7a6;basedOn; +584a81be8fddee4a8ac1d2ba;584a81be8fddee4a8ac1d2b7;584a81be8fddee4a8ac1d2b3;basedOn; +584a81be8fddee4a8ac1d089;584a81be8fddee4a8ac1d086;584a81be8fddee4a8ac1d082;basedOn; +584a81be8fddee4a8ac1d137;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1d130;basedOn; +584a81be8fddee4a8ac1d3c8;584a81be8fddee4a8ac1d3c5;584a81be8fddee4a8ac1d3c1;basedOn; +584a81be8fddee4a8ac1d462;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1d45b;basedOn; +584a81be8fddee4a8ac1d482;584a81be8fddee4a8ac1d47f;584a81be8fddee4a8ac1d47b;basedOn; +584a81be8fddee4a8ac1d011;584a81be8fddee4a8ac1d00e;584a81be8fddee4a8ac1d00a;basedOn; +584a81be8fddee4a8ac1d660;584a81be8fddee4a8ac1d65d;584a81be8fddee4a8ac1d659;basedOn; +584a81be8fddee4a8ac1d498;584a81be8fddee4a8ac1d495;584a81be8fddee4a8ac1d491;basedOn; +584a81be8fddee4a8ac1d676;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1d66f;basedOn; +584a81be8fddee4a8ac1d09f;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1d098;basedOn; +584a81be8fddee4a8ac1d18d;584a81be8fddee4a8ac1d18a;584a81be8fddee4a8ac1d186;basedOn; +584a81be8fddee4a8ac1d4bd;584a81be8fddee4a8ac1d4ba;584a81be8fddee4a8ac1d4b6;basedOn; +584a81be8fddee4a8ac1d3b2;584a81be8fddee4a8ac1d3af;584a81be8fddee4a8ac1d3ab;basedOn; +584a81be8fddee4a8ac1cffb;584a81be8fddee4a8ac1cff8;584a81be8fddee4a8ac1cff4;basedOn; +584a81be8fddee4a8ac1cf10;584a81be8fddee4a8ac1cf0d;584a81be8fddee4a8ac1cf09;basedOn; +584a81be8fddee4a8ac1d4e7;584a81be8fddee4a8ac1d4e4;584a81be8fddee4a8ac1d4e0;basedOn; +584a81be8fddee4a8ac1d397;584a81be8fddee4a8ac1d394;584a81be8fddee4a8ac1d390;basedOn; +584a81be8fddee4a8ac1cfe5;584a81be8fddee4a8ac1cfe2;584a81be8fddee4a8ac1cfde;basedOn; +584a81be8fddee4a8ac1d4fd;584a81be8fddee4a8ac1d4fa;584a81be8fddee4a8ac1d4f6;basedOn; +584a81be8fddee4a8ac1d797;584a81be8fddee4a8ac1d794;584a81be8fddee4a8ac1d790;basedOn; +584a81be8fddee4a8ac1cfcf;584a81be8fddee4a8ac1cfcc;584a81be8fddee4a8ac1cfc8;basedOn; +584a81be8fddee4a8ac1d724;584a81be8fddee4a8ac1d721;584a81be8fddee4a8ac1d71d;basedOn; +584a81be8fddee4a8ac1cf57;584a81be8fddee4a8ac1cf54;584a81be8fddee4a8ac1cf50;basedOn; +584a81be8fddee4a8ac1d2a4;584a81be8fddee4a8ac1d2a1;584a81be8fddee4a8ac1d29d;basedOn; +584a81be8fddee4a8ac1d68c;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1d685;basedOn; +584a81be8fddee4a8ac1d1ea;584a81be8fddee4a8ac1d1e7;584a81be8fddee4a8ac1d1e3;basedOn; +584a81be8fddee4a8ac1ee8e;584a81be8fddee4a8ac1ee8d;584a81be8fddee4a8ac1d1d1;concerns; +584a81be8fddee4a8ac1eb53;584a81be8fddee4a8ac1eb52;584a81be8fddee4a8ac1d09c;concerns; +584a81be8fddee4a8ac1e7b4;584a81be8fddee4a8ac1e7b3;584a81be8fddee4a8ac1cf6a;concerns; +584a81be8fddee4a8ac1ecd7;584a81be8fddee4a8ac1ecd6;584a81be8fddee4a8ac1d134;concerns; +584a81be8fddee4a8ac1f62c;584a81be8fddee4a8ac1f62a;584a81be8fddee4a8ac1d45f;concerns; +584a81be8fddee4a8ac1ea30;584a81be8fddee4a8ac1ea2f;584a81be8fddee4a8ac1d029;concerns; +584a81be8fddee4a8ac1fc8f;584a81be8fddee4a8ac1fc8e;584a81be8fddee4a8ac1d5be;concerns; +584a81be8fddee4a8ac1e816;584a81be8fddee4a8ac1e815;584a81be8fddee4a8ac1cf85;concerns; +584a81be8fddee4a8ac1f371;584a81be8fddee4a8ac1f370;584a81be8fddee4a8ac1d31e;concerns; +584a81be8fddee4a8ac1e440;584a81be8fddee4a8ac1e43d;584a81be8fddee4a8ac1cf23;concerns; +584a81be8fddee4a8ac1ebb4;584a81be8fddee4a8ac1ebb3;584a81be8fddee4a8ac1d0b7;concerns; +584a81be8fddee4a8ac1ede7;584a81be8fddee4a8ac1ede6;584a81be8fddee4a8ac1d1a5;concerns; +584a81be8fddee4a8ac1fd97;584a81be8fddee4a8ac1fd96;584a81be8fddee4a8ac1d673;concerns; +584a81be8fddee4a8ac1fde1;584a81be8fddee4a8ac1fde0;584a81be8fddee4a8ac1d689;concerns; +584a81be8fddee4a8ac1e8c6;584a81be8fddee4a8ac1e8c5;584a81be8fddee4a8ac1cfb6;concerns; +584a81be8fddee4a8ac1f01a;584a81be8fddee4a8ac1f019;584a81be8fddee4a8ac1d28b;concerns; +584a81be8fddee4a8ac1fbc5;584a81be8fddee4a8ac1fbc4;584a81be8fddee4a8ac1d552;concerns; +584a81be8fddee4a8ac1e8a8;584a81be8fddee4a8ac1e8a6;584a81be8fddee4a8ac1cfb6;concerns; +584a81be8fddee4a8ac1d72c;584a81be8fddee4a8ac1d72b;584a81be8fddee4a8ac1d726;contains; +584a81be8fddee4a8ac1d742;584a81be8fddee4a8ac1d741;584a81be8fddee4a8ac1d73c;contains; +584a81be8fddee4a8ac1d75d;584a81be8fddee4a8ac1d75c;584a81be8fddee4a8ac1d757;contains; +584a81be8fddee4a8ac1d773;584a81be8fddee4a8ac1d772;584a81be8fddee4a8ac1d76d;contains; +584a81be8fddee4a8ac1d789;584a81be8fddee4a8ac1d788;584a81be8fddee4a8ac1d783;contains; +584a81be8fddee4a8ac1cf75;584a81be8fddee4a8ac1cf74;584a81be8fddee4a8ac1cf6f;contains; +584a81be8fddee4a8ac1d79f;584a81be8fddee4a8ac1d79e;584a81be8fddee4a8ac1d799;contains; +584a81be8fddee4a8ac1d7b5;584a81be8fddee4a8ac1d7b4;584a81be8fddee4a8ac1d7af;contains; +584a81be8fddee4a8ac1d7cb;584a81be8fddee4a8ac1d7ca;584a81be8fddee4a8ac1d7c5;contains; +584a81be8fddee4a8ac1d7e1;584a81be8fddee4a8ac1d7e0;584a81be8fddee4a8ac1d7db;contains; +584a81be8fddee4a8ac1d7fc;584a81be8fddee4a8ac1d7fb;584a81be8fddee4a8ac1d7f6;contains; +584a81be8fddee4a8ac1cf2e;584a81be8fddee4a8ac1cf2d;584a81be8fddee4a8ac1cf28;contains; +584a81be8fddee4a8ac1cf75;584a81be8fddee4a8ac1cf74;584a81be8fddee4a8ac1cf6f;contains; +584a81be8fddee4a8ac1cf90;584a81be8fddee4a8ac1cf8f;584a81be8fddee4a8ac1cf8a;contains; +584a81be8fddee4a8ac1cfa6;584a81be8fddee4a8ac1cfa5;584a81be8fddee4a8ac1cfa0;contains; +584a81be8fddee4a8ac1cfc1;584a81be8fddee4a8ac1cfc0;584a81be8fddee4a8ac1cfbb;contains; +584a81be8fddee4a8ac1cfd7;584a81be8fddee4a8ac1cfd6;584a81be8fddee4a8ac1cfd1;contains; +584a81be8fddee4a8ac1cfed;584a81be8fddee4a8ac1cfec;584a81be8fddee4a8ac1cfe7;contains; +584a81be8fddee4a8ac1d003;584a81be8fddee4a8ac1d002;584a81be8fddee4a8ac1cffd;contains; +584a81be8fddee4a8ac1d019;584a81be8fddee4a8ac1d018;584a81be8fddee4a8ac1d013;contains; +584a81be8fddee4a8ac1d5c9;584a81be8fddee4a8ac1d5c8;584a81be8fddee4a8ac1d5c3;contains; +584a81be8fddee4a8ac1cebb;584a81be8fddee4a8ac1ceba;584a81be8fddee4a8ac1ceb5;contains; +584a81be8fddee4a8ac1d034;584a81be8fddee4a8ac1d033;584a81be8fddee4a8ac1d02e;contains; +584a81be8fddee4a8ac1d04a;584a81be8fddee4a8ac1d049;584a81be8fddee4a8ac1d044;contains; +584a81be8fddee4a8ac1d065;584a81be8fddee4a8ac1d064;584a81be8fddee4a8ac1d05f;contains; +584a81be8fddee4a8ac1d07b;584a81be8fddee4a8ac1d07a;584a81be8fddee4a8ac1d075;contains; +584a81be8fddee4a8ac1d55d;584a81be8fddee4a8ac1d55c;584a81be8fddee4a8ac1d557;contains; +584a81be8fddee4a8ac1d091;584a81be8fddee4a8ac1d090;584a81be8fddee4a8ac1d08b;contains; +584a81be8fddee4a8ac1d0a7;584a81be8fddee4a8ac1d0a6;584a81be8fddee4a8ac1d0a1;contains; +584a81be8fddee4a8ac1d0c2;584a81be8fddee4a8ac1d0c1;584a81be8fddee4a8ac1d0bc;contains; +584a81be8fddee4a8ac1d0dd;584a81be8fddee4a8ac1d0dc;584a81be8fddee4a8ac1d0d7;contains; +584a81be8fddee4a8ac1d0f3;584a81be8fddee4a8ac1d0f2;584a81be8fddee4a8ac1d0ed;contains; +584a81be8fddee4a8ac1d109;584a81be8fddee4a8ac1d108;584a81be8fddee4a8ac1d103;contains; +584a81be8fddee4a8ac1d694;584a81be8fddee4a8ac1d693;584a81be8fddee4a8ac1d68e;contains; +584a81be8fddee4a8ac1d46a;584a81be8fddee4a8ac1d469;584a81be8fddee4a8ac1d464;contains; +584a81be8fddee4a8ac1d129;584a81be8fddee4a8ac1d128;584a81be8fddee4a8ac1d123;contains; +584a81be8fddee4a8ac1d13f;584a81be8fddee4a8ac1d13e;584a81be8fddee4a8ac1d139;contains; +584a81be8fddee4a8ac1d169;584a81be8fddee4a8ac1d168;584a81be8fddee4a8ac1d163;contains; +584a81be8fddee4a8ac1d17f;584a81be8fddee4a8ac1d17e;584a81be8fddee4a8ac1d179;contains; +584a81be8fddee4a8ac1d195;584a81be8fddee4a8ac1d194;584a81be8fddee4a8ac1d18f;contains; +584a81be8fddee4a8ac1d1b0;584a81be8fddee4a8ac1d1af;584a81be8fddee4a8ac1d1aa;contains; +584a81be8fddee4a8ac1d329;584a81be8fddee4a8ac1d328;584a81be8fddee4a8ac1d323;contains; +584a81be8fddee4a8ac1d1c6;584a81be8fddee4a8ac1d1c5;584a81be8fddee4a8ac1d1c0;contains; +584a81be8fddee4a8ac1d1dc;584a81be8fddee4a8ac1d1db;584a81be8fddee4a8ac1d1d6;contains; +584a81be8fddee4a8ac1d1f2;584a81be8fddee4a8ac1d1f1;584a81be8fddee4a8ac1d1ec;contains; +584a81be8fddee4a8ac1d208;584a81be8fddee4a8ac1d207;584a81be8fddee4a8ac1d202;contains; +584a81be8fddee4a8ac1d296;584a81be8fddee4a8ac1d295;584a81be8fddee4a8ac1d290;contains; +584a81be8fddee4a8ac1d21e;584a81be8fddee4a8ac1d21d;584a81be8fddee4a8ac1d218;contains; +584a81be8fddee4a8ac1ced6;584a81be8fddee4a8ac1ced5;584a81be8fddee4a8ac1ced0;contains; +584a81be8fddee4a8ac1d234;584a81be8fddee4a8ac1d233;584a81be8fddee4a8ac1d22e;contains; +584a81be8fddee4a8ac1d24a;584a81be8fddee4a8ac1d249;584a81be8fddee4a8ac1d244;contains; +584a81be8fddee4a8ac1d260;584a81be8fddee4a8ac1d25f;584a81be8fddee4a8ac1d25a;contains; +584a81be8fddee4a8ac1d280;584a81be8fddee4a8ac1d27f;584a81be8fddee4a8ac1d27a;contains; +584a81be8fddee4a8ac1d296;584a81be8fddee4a8ac1d295;584a81be8fddee4a8ac1d290;contains; +584a81be8fddee4a8ac1d2ac;584a81be8fddee4a8ac1d2ab;584a81be8fddee4a8ac1d2a6;contains; +584a81be8fddee4a8ac1d1dc;584a81be8fddee4a8ac1d1db;584a81be8fddee4a8ac1d1d6;contains; +584a81be8fddee4a8ac1d2c2;584a81be8fddee4a8ac1d2c1;584a81be8fddee4a8ac1d2bc;contains; +584a81be8fddee4a8ac1d2ee;584a81be8fddee4a8ac1d2ed;584a81be8fddee4a8ac1d2e8;contains; +584a81be8fddee4a8ac1d30e;584a81be8fddee4a8ac1d30d;584a81be8fddee4a8ac1d308;contains; +584a81be8fddee4a8ac1d329;584a81be8fddee4a8ac1d328;584a81be8fddee4a8ac1d323;contains; +584a81be8fddee4a8ac1ceec;584a81be8fddee4a8ac1ceeb;584a81be8fddee4a8ac1cee6;contains; +584a81be8fddee4a8ac1d1b0;584a81be8fddee4a8ac1d1af;584a81be8fddee4a8ac1d1aa;contains; +584a81be8fddee4a8ac1d33f;584a81be8fddee4a8ac1d33e;584a81be8fddee4a8ac1d339;contains; +584a81be8fddee4a8ac1d35a;584a81be8fddee4a8ac1d359;584a81be8fddee4a8ac1d354;contains; +584a81be8fddee4a8ac1d37a;584a81be8fddee4a8ac1d379;584a81be8fddee4a8ac1d374;contains; +584a81be8fddee4a8ac1d39f;584a81be8fddee4a8ac1d39e;584a81be8fddee4a8ac1d399;contains; +584a81be8fddee4a8ac1cf02;584a81be8fddee4a8ac1cf01;584a81be8fddee4a8ac1cefc;contains; +584a81be8fddee4a8ac1d3ba;584a81be8fddee4a8ac1d3b9;584a81be8fddee4a8ac1d3b4;contains; +584a81be8fddee4a8ac1d3d0;584a81be8fddee4a8ac1d3cf;584a81be8fddee4a8ac1d3ca;contains; +584a81be8fddee4a8ac1d13f;584a81be8fddee4a8ac1d13e;584a81be8fddee4a8ac1d139;contains; +584a81be8fddee4a8ac1d3e6;584a81be8fddee4a8ac1d3e5;584a81be8fddee4a8ac1d3e0;contains; +584a81be8fddee4a8ac1d3fc;584a81be8fddee4a8ac1d3fb;584a81be8fddee4a8ac1d3f6;contains; +584a81be8fddee4a8ac1d412;584a81be8fddee4a8ac1d411;584a81be8fddee4a8ac1d40c;contains; +584a81be8fddee4a8ac1d428;584a81be8fddee4a8ac1d427;584a81be8fddee4a8ac1d422;contains; +584a81be8fddee4a8ac1d43e;584a81be8fddee4a8ac1d43d;584a81be8fddee4a8ac1d438;contains; +584a81be8fddee4a8ac1d454;584a81be8fddee4a8ac1d453;584a81be8fddee4a8ac1d44e;contains; +584a81be8fddee4a8ac1d46a;584a81be8fddee4a8ac1d469;584a81be8fddee4a8ac1d464;contains; +584a81be8fddee4a8ac1d48a;584a81be8fddee4a8ac1d489;584a81be8fddee4a8ac1d484;contains; +584a81be8fddee4a8ac1d0c2;584a81be8fddee4a8ac1d0c1;584a81be8fddee4a8ac1d0bc;contains; +584a81be8fddee4a8ac1d4a0;584a81be8fddee4a8ac1d49f;584a81be8fddee4a8ac1d49a;contains; +584a81be8fddee4a8ac1cf18;584a81be8fddee4a8ac1cf17;584a81be8fddee4a8ac1cf12;contains; +584a81be8fddee4a8ac1d4c5;584a81be8fddee4a8ac1d4c4;584a81be8fddee4a8ac1d4bf;contains; +584a81be8fddee4a8ac1cea5;584a81be8fddee4a8ac1cea4;584a81be8fddee4a8ac1ce9f;contains; +584a81be8fddee4a8ac1d4ef;584a81be8fddee4a8ac1d4ee;584a81be8fddee4a8ac1d4e9;contains; +584a81be8fddee4a8ac1d505;584a81be8fddee4a8ac1d504;584a81be8fddee4a8ac1d4ff;contains; +584a81be8fddee4a8ac1d0a7;584a81be8fddee4a8ac1d0a6;584a81be8fddee4a8ac1d0a1;contains; +584a81be8fddee4a8ac1d51b;584a81be8fddee4a8ac1d51a;584a81be8fddee4a8ac1d515;contains; +584a81be8fddee4a8ac1d531;584a81be8fddee4a8ac1d530;584a81be8fddee4a8ac1d52b;contains; +584a81be8fddee4a8ac1d547;584a81be8fddee4a8ac1d546;584a81be8fddee4a8ac1d541;contains; +584a81be8fddee4a8ac1d034;584a81be8fddee4a8ac1d033;584a81be8fddee4a8ac1d02e;contains; +584a81be8fddee4a8ac1d55d;584a81be8fddee4a8ac1d55c;584a81be8fddee4a8ac1d557;contains; +584a81be8fddee4a8ac1d578;584a81be8fddee4a8ac1d577;584a81be8fddee4a8ac1d572;contains; +584a81be8fddee4a8ac1d58e;584a81be8fddee4a8ac1d58d;584a81be8fddee4a8ac1d588;contains; +584a81be8fddee4a8ac1d5a4;584a81be8fddee4a8ac1d5a3;584a81be8fddee4a8ac1d59e;contains; +584a81be8fddee4a8ac1cf2e;584a81be8fddee4a8ac1cf2d;584a81be8fddee4a8ac1cf28;contains; +584a81be8fddee4a8ac1d5c9;584a81be8fddee4a8ac1d5c8;584a81be8fddee4a8ac1d5c3;contains; +584a81be8fddee4a8ac1d5e4;584a81be8fddee4a8ac1d5e3;584a81be8fddee4a8ac1d5de;contains; +584a81be8fddee4a8ac1d67e;584a81be8fddee4a8ac1d67d;584a81be8fddee4a8ac1d678;contains; +584a81be8fddee4a8ac1d5fa;584a81be8fddee4a8ac1d5f9;584a81be8fddee4a8ac1d5f4;contains; +584a81be8fddee4a8ac1cf49;584a81be8fddee4a8ac1cf48;584a81be8fddee4a8ac1cf43;contains; +584a81be8fddee4a8ac1d610;584a81be8fddee4a8ac1d60f;584a81be8fddee4a8ac1d60a;contains; +584a81be8fddee4a8ac1d626;584a81be8fddee4a8ac1d625;584a81be8fddee4a8ac1d620;contains; +584a81be8fddee4a8ac1d63c;584a81be8fddee4a8ac1d63b;584a81be8fddee4a8ac1d636;contains; +584a81be8fddee4a8ac1d652;584a81be8fddee4a8ac1d651;584a81be8fddee4a8ac1d64c;contains; +584a81be8fddee4a8ac1d668;584a81be8fddee4a8ac1d667;584a81be8fddee4a8ac1d662;contains; +584a81be8fddee4a8ac1cfc1;584a81be8fddee4a8ac1cfc0;584a81be8fddee4a8ac1cfbb;contains; +584a81be8fddee4a8ac1d67e;584a81be8fddee4a8ac1d67d;584a81be8fddee4a8ac1d678;contains; +584a81be8fddee4a8ac1d694;584a81be8fddee4a8ac1d693;584a81be8fddee4a8ac1d68e;contains; +584a81be8fddee4a8ac1d6af;584a81be8fddee4a8ac1d6ae;584a81be8fddee4a8ac1d6a9;contains; +584a81be8fddee4a8ac1cf90;584a81be8fddee4a8ac1cf8f;584a81be8fddee4a8ac1cf8a;contains; +584a81be8fddee4a8ac1d6cf;584a81be8fddee4a8ac1d6ce;584a81be8fddee4a8ac1d6c9;contains; +584a81be8fddee4a8ac1d6e5;584a81be8fddee4a8ac1d6e4;584a81be8fddee4a8ac1d6df;contains; +584a81be8fddee4a8ac1d6fb;584a81be8fddee4a8ac1d6fa;584a81be8fddee4a8ac1d6f5;contains; +584a81be8fddee4a8ac1d716;584a81be8fddee4a8ac1d715;584a81be8fddee4a8ac1d710;contains; +584a81be8fddee4a8ac1cf5f;584a81be8fddee4a8ac1cf5e;584a81be8fddee4a8ac1cf59;contains; +584a81be8fddee4a8ac1d2d8;584a81be8fddee4a8ac1d2d7;584a81be8fddee4a8ac1d2d2;contains; +584a81be8fddee4a8ac1e81b;584a81be8fddee4a8ac1e815;584a81be8fddee4a8ac1e818;createdBy; +584a81be8fddee4a8ac1fd9a;584a81be8fddee4a8ac1fd96;584a81be8fddee4a8ac1fd98;createdBy; +584a81be8fddee4a8ac1e7bf;584a81be8fddee4a8ac1e7b3;584a81be8fddee4a8ac1e7bd;createdBy; +584a81be8fddee4a8ac1e8c9;584a81be8fddee4a8ac1e8c5;584a81be8fddee4a8ac1e8c7;createdBy; +584a81be8fddee4a8ac1f642;584a81be8fddee4a8ac1f62a;584a81be8fddee4a8ac1f640;createdBy; +584a81be8fddee4a8ac1ebb8;584a81be8fddee4a8ac1ebb3;584a81be8fddee4a8ac1ebb5;createdBy; +584a81be8fddee4a8ac1edf1;584a81be8fddee4a8ac1ede6;584a81be8fddee4a8ac1edee;createdBy; +584a81be8fddee4a8ac1ee9d;584a81be8fddee4a8ac1ee8d;584a81be8fddee4a8ac1ee99;createdBy; +584a81be8fddee4a8ac1fbd1;584a81be8fddee4a8ac1fbc4;584a81be8fddee4a8ac1fbcf;createdBy; +584a81be8fddee4a8ac1ecdb;584a81be8fddee4a8ac1ecd6;584a81be8fddee4a8ac1ecd9;createdBy; +584a81be8fddee4a8ac1fde7;584a81be8fddee4a8ac1fde0;584a81be8fddee4a8ac1fde5;createdBy; +584a81be8fddee4a8ac1f02a;584a81be8fddee4a8ac1f019;584a81be8fddee4a8ac1f027;createdBy; +584a81be8fddee4a8ac1f381;584a81be8fddee4a8ac1f370;584a81be8fddee4a8ac1f37e;createdBy; +584a81be8fddee4a8ac1e8ae;584a81be8fddee4a8ac1e8a6;584a81be8fddee4a8ac1e8ac;createdBy; +584a81be8fddee4a8ac1e44d;584a81be8fddee4a8ac1e43d;584a81be8fddee4a8ac1e449;createdBy; +584a81be8fddee4a8ac1ea3c;584a81be8fddee4a8ac1ea2f;584a81be8fddee4a8ac1ea39;createdBy; +584a81be8fddee4a8ac1eb72;584a81be8fddee4a8ac1eb52;584a81be8fddee4a8ac1eb59;createdBy; +584a81be8fddee4a8ac1fc94;584a81be8fddee4a8ac1fc8e;584a81be8fddee4a8ac1fc91;createdBy; +584a81be8fddee4a8ac1d7ce;584a81be8fddee4a8ac1d7cd;584a81be8fddee4a8ac1d7c5;createdFor; +584a81be8fddee4a8ac1d520;584a81be8fddee4a8ac1d51f;584a81be8fddee4a8ac1d510;createdFor; +584a81be8fddee4a8ac1e829;584a81be8fddee4a8ac1e828;584a81be8fddee4a8ac1cf85;createdFor; +584a81be8fddee4a8ac1d12e;584a81be8fddee4a8ac1d12d;584a81be8fddee4a8ac1d11e;createdFor; +584a81be8fddee4a8ac1cfc4;584a81be8fddee4a8ac1cfc3;584a81be8fddee4a8ac1cfbb;createdFor; +584a81be8fddee4a8ac1d12c;584a81be8fddee4a8ac1d12b;584a81be8fddee4a8ac1d123;createdFor; +584a81be8fddee4a8ac1d184;584a81be8fddee4a8ac1d183;584a81be8fddee4a8ac1d174;createdFor; +584a81be8fddee4a8ac1d534;584a81be8fddee4a8ac1d533;584a81be8fddee4a8ac1d52b;createdFor; +584a81be8fddee4a8ac1d536;584a81be8fddee4a8ac1d535;584a81be8fddee4a8ac1d526;createdFor; +584a81be8fddee4a8ac1d2f1;584a81be8fddee4a8ac1d2f0;584a81be8fddee4a8ac1d2e8;createdFor; +584a81be8fddee4a8ac1d2f3;584a81be8fddee4a8ac1d2f2;584a81be8fddee4a8ac1d2e3;createdFor; +584a81be8fddee4a8ac1d641;584a81be8fddee4a8ac1d640;584a81be8fddee4a8ac1d631;createdFor; +584a81be8fddee4a8ac1d63f;584a81be8fddee4a8ac1d63e;584a81be8fddee4a8ac1d636;createdFor; +584a81be8fddee4a8ac1d7d0;584a81be8fddee4a8ac1d7cf;584a81be8fddee4a8ac1d7c0;createdFor; +584a81be8fddee4a8ac1d54c;584a81be8fddee4a8ac1d54b;584a81be8fddee4a8ac1d53c;createdFor; +584a81be8fddee4a8ac1d1b3;584a81be8fddee4a8ac1d1b2;584a81be8fddee4a8ac1d1aa;createdFor; +584a81be8fddee4a8ac1d719;584a81be8fddee4a8ac1d718;584a81be8fddee4a8ac1d710;createdFor; +584a81be8fddee4a8ac1d54a;584a81be8fddee4a8ac1d549;584a81be8fddee4a8ac1d541;createdFor; +584a81be8fddee4a8ac1d71b;584a81be8fddee4a8ac1d71a;584a81be8fddee4a8ac1d70b;createdFor; +584a81be8fddee4a8ac1cfab;584a81be8fddee4a8ac1cfaa;584a81be8fddee4a8ac1cf9b;createdFor; +584a81be8fddee4a8ac1cfa9;584a81be8fddee4a8ac1cfa8;584a81be8fddee4a8ac1cfa0;createdFor; +584a81be8fddee4a8ac1d20d;584a81be8fddee4a8ac1d20c;584a81be8fddee4a8ac1d1fd;createdFor; +584a81be8fddee4a8ac1d747;584a81be8fddee4a8ac1d746;584a81be8fddee4a8ac1d737;createdFor; +584a81be8fddee4a8ac1d560;584a81be8fddee4a8ac1d55f;584a81be8fddee4a8ac1d557;createdFor; +584a81be8fddee4a8ac1d562;584a81be8fddee4a8ac1d561;584a81be8fddee4a8ac1d552;createdFor; +584a81be8fddee4a8ac1d1b5;584a81be8fddee4a8ac1d1b4;584a81be8fddee4a8ac1d1a5;createdFor; +584a81be8fddee4a8ac1f663;584a81be8fddee4a8ac1f662;584a81be8fddee4a8ac1d464;createdFor; +584a81be8fddee4a8ac1ea67;584a81be8fddee4a8ac1ea66;584a81be8fddee4a8ac1d02e;createdFor; +584a81be8fddee4a8ac1d57b;584a81be8fddee4a8ac1d57a;584a81be8fddee4a8ac1d572;createdFor; +584a81be8fddee4a8ac1d57d;584a81be8fddee4a8ac1d57c;584a81be8fddee4a8ac1d56d;createdFor; +584a81be8fddee4a8ac1ea5b;584a81be8fddee4a8ac1ea5a;584a81be8fddee4a8ac1d029;createdFor; +584a81be8fddee4a8ac1e8c1;584a81be8fddee4a8ac1e8c0;584a81be8fddee4a8ac1cfbb;createdFor; +584a81be8fddee4a8ac1d62b;584a81be8fddee4a8ac1d62a;584a81be8fddee4a8ac1d61b;createdFor; +584a81be8fddee4a8ac1cf95;584a81be8fddee4a8ac1cf94;584a81be8fddee4a8ac1cf85;createdFor; +584a81be8fddee4a8ac1d591;584a81be8fddee4a8ac1d590;584a81be8fddee4a8ac1d588;createdFor; +584a81be8fddee4a8ac1d593;584a81be8fddee4a8ac1d592;584a81be8fddee4a8ac1d583;createdFor; +584a81be8fddee4a8ac1d629;584a81be8fddee4a8ac1d628;584a81be8fddee4a8ac1d620;createdFor; +584a81be8fddee4a8ac1cf93;584a81be8fddee4a8ac1cf92;584a81be8fddee4a8ac1cf8a;createdFor; +584a81be8fddee4a8ac1d198;584a81be8fddee4a8ac1d197;584a81be8fddee4a8ac1d18f;createdFor; +584a81be8fddee4a8ac1e484;584a81be8fddee4a8ac1e483;584a81be8fddee4a8ac1cf28;createdFor; +584a81be8fddee4a8ac1fca8;584a81be8fddee4a8ac1fca7;584a81be8fddee4a8ac1d5c3;createdFor; +584a81be8fddee4a8ac1d5a7;584a81be8fddee4a8ac1d5a6;584a81be8fddee4a8ac1d59e;createdFor; +584a81be8fddee4a8ac1d5a9;584a81be8fddee4a8ac1d5a8;584a81be8fddee4a8ac1d599;createdFor; +584a81be8fddee4a8ac1cef1;584a81be8fddee4a8ac1cef0;584a81be8fddee4a8ac1cee1;createdFor; +584a81be8fddee4a8ac1d10e;584a81be8fddee4a8ac1d10d;584a81be8fddee4a8ac1d0fe;createdFor; +584a81be8fddee4a8ac1cf7a;584a81be8fddee4a8ac1cf79;584a81be8fddee4a8ac1cf6a;createdFor; +584a81be8fddee4a8ac1cf78;584a81be8fddee4a8ac1cf77;584a81be8fddee4a8ac1cf6f;createdFor; +584a81be8fddee4a8ac1f3a5;584a81be8fddee4a8ac1f3a4;584a81be8fddee4a8ac1d323;createdFor; +584a81be8fddee4a8ac1d615;584a81be8fddee4a8ac1d614;584a81be8fddee4a8ac1d605;createdFor; +584a81be8fddee4a8ac1d613;584a81be8fddee4a8ac1d612;584a81be8fddee4a8ac1d60a;createdFor; +584a81be8fddee4a8ac1d1f7;584a81be8fddee4a8ac1d1f6;584a81be8fddee4a8ac1d1e7;createdFor; +584a81be8fddee4a8ac1cf64;584a81be8fddee4a8ac1cf63;584a81be8fddee4a8ac1cf54;createdFor; +584a81be8fddee4a8ac1e47a;584a81be8fddee4a8ac1e479;584a81be8fddee4a8ac1cf23;createdFor; +584a81be8fddee4a8ac1d5cc;584a81be8fddee4a8ac1d5cb;584a81be8fddee4a8ac1d5c3;createdFor; +584a81be8fddee4a8ac1d5ce;584a81be8fddee4a8ac1d5cd;584a81be8fddee4a8ac1d5be;createdFor; +584a81be8fddee4a8ac1d311;584a81be8fddee4a8ac1d310;584a81be8fddee4a8ac1d308;createdFor; +584a81be8fddee4a8ac1d313;584a81be8fddee4a8ac1d312;584a81be8fddee4a8ac1d303;createdFor; +584a81be8fddee4a8ac1d7e4;584a81be8fddee4a8ac1d7e3;584a81be8fddee4a8ac1d7db;createdFor; +584a81be8fddee4a8ac1d801;584a81be8fddee4a8ac1d800;584a81be8fddee4a8ac1d7f1;createdFor; +584a81be8fddee4a8ac1e8e4;584a81be8fddee4a8ac1e8e3;584a81be8fddee4a8ac1cfbb;createdFor; +584a81be8fddee4a8ac1d7ff;584a81be8fddee4a8ac1d7fe;584a81be8fddee4a8ac1d7f6;createdFor; +584a81be8fddee4a8ac1e8de;584a81be8fddee4a8ac1e8dd;584a81be8fddee4a8ac1cfb6;createdFor; +584a81be8fddee4a8ac1d10c;584a81be8fddee4a8ac1d10b;584a81be8fddee4a8ac1d103;createdFor; +584a81be8fddee4a8ac1d5e7;584a81be8fddee4a8ac1d5e6;584a81be8fddee4a8ac1d5de;createdFor; +584a81be8fddee4a8ac1d5e9;584a81be8fddee4a8ac1d5e8;584a81be8fddee4a8ac1d5d9;createdFor; +584a81be8fddee4a8ac1d7e6;584a81be8fddee4a8ac1d7e5;584a81be8fddee4a8ac1d7d6;createdFor; +584a81be8fddee4a8ac1cf62;584a81be8fddee4a8ac1cf61;584a81be8fddee4a8ac1cf59;createdFor; +584a81be8fddee4a8ac1d5fd;584a81be8fddee4a8ac1d5fc;584a81be8fddee4a8ac1d5f4;createdFor; +584a81be8fddee4a8ac1d5ff;584a81be8fddee4a8ac1d5fe;584a81be8fddee4a8ac1d5ef;createdFor; +584a81be8fddee4a8ac1e8ba;584a81be8fddee4a8ac1e8b9;584a81be8fddee4a8ac1cfb6;createdFor; +584a81be8fddee4a8ac1d1f5;584a81be8fddee4a8ac1d1f4;584a81be8fddee4a8ac1d1ec;createdFor; +584a81be8fddee4a8ac1fdab;584a81be8fddee4a8ac1fdaa;584a81be8fddee4a8ac1d678;createdFor; +584a81be8fddee4a8ac1d0f8;584a81be8fddee4a8ac1d0f7;584a81be8fddee4a8ac1d0e8;createdFor; +584a81be8fddee4a8ac1d0f6;584a81be8fddee4a8ac1d0f5;584a81be8fddee4a8ac1d0ed;createdFor; +584a81be8fddee4a8ac1ee16;584a81be8fddee4a8ac1ee15;584a81be8fddee4a8ac1d1aa;createdFor; +584a81be8fddee4a8ac1d762;584a81be8fddee4a8ac1d761;584a81be8fddee4a8ac1d752;createdFor; +584a81be8fddee4a8ac1f044;584a81be8fddee4a8ac1f043;584a81be8fddee4a8ac1d28b;createdFor; +584a81be8fddee4a8ac1d32c;584a81be8fddee4a8ac1d32b;584a81be8fddee4a8ac1d323;createdFor; +584a81be8fddee4a8ac1d32e;584a81be8fddee4a8ac1d32d;584a81be8fddee4a8ac1d31e;createdFor; +584a81be8fddee4a8ac1e7c7;584a81be8fddee4a8ac1e7c6;584a81be8fddee4a8ac1cf6a;createdFor; +584a81be8fddee4a8ac1d16e;584a81be8fddee4a8ac1d16d;584a81be8fddee4a8ac1d15e;createdFor; +584a81be8fddee4a8ac1d0e2;584a81be8fddee4a8ac1d0e1;584a81be8fddee4a8ac1d0d2;createdFor; +584a81be8fddee4a8ac1f658;584a81be8fddee4a8ac1f657;584a81be8fddee4a8ac1d45f;createdFor; +584a81be8fddee4a8ac1f048;584a81be8fddee4a8ac1f047;584a81be8fddee4a8ac1d290;createdFor; +584a81be8fddee4a8ac1d0e0;584a81be8fddee4a8ac1d0df;584a81be8fddee4a8ac1d0d7;createdFor; +584a81be8fddee4a8ac1d342;584a81be8fddee4a8ac1d341;584a81be8fddee4a8ac1d339;createdFor; +584a81be8fddee4a8ac1d344;584a81be8fddee4a8ac1d343;584a81be8fddee4a8ac1d334;createdFor; +584a81be8fddee4a8ac1d283;584a81be8fddee4a8ac1d282;584a81be8fddee4a8ac1d27a;createdFor; +584a81be8fddee4a8ac1d35d;584a81be8fddee4a8ac1d35c;584a81be8fddee4a8ac1d354;createdFor; +584a81be8fddee4a8ac1d35f;584a81be8fddee4a8ac1d35e;584a81be8fddee4a8ac1d34f;createdFor; +584a81be8fddee4a8ac1d285;584a81be8fddee4a8ac1d284;584a81be8fddee4a8ac1d275;createdFor; +584a81be8fddee4a8ac1ee11;584a81be8fddee4a8ac1ee10;584a81be8fddee4a8ac1d1a5;createdFor; +584a81be8fddee4a8ac1d1e1;584a81be8fddee4a8ac1d1e0;584a81be8fddee4a8ac1d1d1;createdFor; +584a81be8fddee4a8ac1d1df;584a81be8fddee4a8ac1d1de;584a81be8fddee4a8ac1d1d6;createdFor; +584a81be8fddee4a8ac1cec0;584a81be8fddee4a8ac1cebf;584a81be8fddee4a8ac1ceb0;createdFor; +584a81be8fddee4a8ac1d1c9;584a81be8fddee4a8ac1d1c8;584a81be8fddee4a8ac1d1c0;createdFor; +584a81be8fddee4a8ac1fda8;584a81be8fddee4a8ac1fda7;584a81be8fddee4a8ac1d673;createdFor; +584a81be8fddee4a8ac1d16c;584a81be8fddee4a8ac1d16b;584a81be8fddee4a8ac1d163;createdFor; +584a81be8fddee4a8ac1cebe;584a81be8fddee4a8ac1cebd;584a81be8fddee4a8ac1ceb5;createdFor; +584a81be8fddee4a8ac1fdf1;584a81be8fddee4a8ac1fdf0;584a81be8fddee4a8ac1d689;createdFor; +584a81be8fddee4a8ac1d37d;584a81be8fddee4a8ac1d37c;584a81be8fddee4a8ac1d374;createdFor; +584a81be8fddee4a8ac1d37f;584a81be8fddee4a8ac1d37e;584a81be8fddee4a8ac1d36f;createdFor; +584a81be8fddee4a8ac1d1cb;584a81be8fddee4a8ac1d1ca;584a81be8fddee4a8ac1d1bb;createdFor; +584a81be8fddee4a8ac1d0c7;584a81be8fddee4a8ac1d0c6;584a81be8fddee4a8ac1d0b7;createdFor; +584a81be8fddee4a8ac1d0c5;584a81be8fddee4a8ac1d0c4;584a81be8fddee4a8ac1d0bc;createdFor; +584a81be8fddee4a8ac1cf05;584a81be8fddee4a8ac1cf04;584a81be8fddee4a8ac1cefc;createdFor; +584a81be8fddee4a8ac1cf07;584a81be8fddee4a8ac1cf06;584a81be8fddee4a8ac1cef7;createdFor; +584a81be8fddee4a8ac1d239;584a81be8fddee4a8ac1d238;584a81be8fddee4a8ac1d229;createdFor; +584a81be8fddee4a8ac1d0aa;584a81be8fddee4a8ac1d0a9;584a81be8fddee4a8ac1d0a1;createdFor; +584a81be8fddee4a8ac1d776;584a81be8fddee4a8ac1d775;584a81be8fddee4a8ac1d76d;createdFor; +584a81be8fddee4a8ac1d19a;584a81be8fddee4a8ac1d199;584a81be8fddee4a8ac1d18a;createdFor; +584a81be8fddee4a8ac1d182;584a81be8fddee4a8ac1d181;584a81be8fddee4a8ac1d179;createdFor; +584a81be8fddee4a8ac1d3a2;584a81be8fddee4a8ac1d3a1;584a81be8fddee4a8ac1d399;createdFor; +584a81be8fddee4a8ac1d3a4;584a81be8fddee4a8ac1d3a3;584a81be8fddee4a8ac1d394;createdFor; +584a81be8fddee4a8ac1d51e;584a81be8fddee4a8ac1d51d;584a81be8fddee4a8ac1d515;createdFor; +584a81be8fddee4a8ac1d778;584a81be8fddee4a8ac1d777;584a81be8fddee4a8ac1d768;createdFor; +584a81be8fddee4a8ac1d299;584a81be8fddee4a8ac1d298;584a81be8fddee4a8ac1d290;createdFor; +584a81be8fddee4a8ac1ecf5;584a81be8fddee4a8ac1ecf4;584a81be8fddee4a8ac1d134;createdFor; +584a81be8fddee4a8ac1d3bd;584a81be8fddee4a8ac1d3bc;584a81be8fddee4a8ac1d3b4;createdFor; +584a81be8fddee4a8ac1d3bf;584a81be8fddee4a8ac1d3be;584a81be8fddee4a8ac1d3af;createdFor; +584a81be8fddee4a8ac1d0ac;584a81be8fddee4a8ac1d0ab;584a81be8fddee4a8ac1d09c;createdFor; +584a81be8fddee4a8ac1d29b;584a81be8fddee4a8ac1d29a;584a81be8fddee4a8ac1d28b;createdFor; +584a81be8fddee4a8ac1d223;584a81be8fddee4a8ac1d222;584a81be8fddee4a8ac1d213;createdFor; +584a81be8fddee4a8ac1d6b4;584a81be8fddee4a8ac1d6b3;584a81be8fddee4a8ac1d6a4;createdFor; +584a81be8fddee4a8ac1d6e8;584a81be8fddee4a8ac1d6e7;584a81be8fddee4a8ac1d6df;createdFor; +584a81be8fddee4a8ac1cedb;584a81be8fddee4a8ac1ceda;584a81be8fddee4a8ac1cecb;createdFor; +584a81be8fddee4a8ac1d096;584a81be8fddee4a8ac1d095;584a81be8fddee4a8ac1d086;createdFor; +584a81be8fddee4a8ac1ceef;584a81be8fddee4a8ac1ceee;584a81be8fddee4a8ac1cee6;createdFor; +584a81be8fddee4a8ac1d3d3;584a81be8fddee4a8ac1d3d2;584a81be8fddee4a8ac1d3ca;createdFor; +584a81be8fddee4a8ac1d3d5;584a81be8fddee4a8ac1d3d4;584a81be8fddee4a8ac1d3c5;createdFor; +584a81be8fddee4a8ac1eeb9;584a81be8fddee4a8ac1eeb8;584a81be8fddee4a8ac1d1d6;createdFor; +584a81be8fddee4a8ac1d094;584a81be8fddee4a8ac1d093;584a81be8fddee4a8ac1d08b;createdFor; +584a81be8fddee4a8ac1d6b2;584a81be8fddee4a8ac1d6b1;584a81be8fddee4a8ac1d6a9;createdFor; +584a81be8fddee4a8ac1d6ea;584a81be8fddee4a8ac1d6e9;584a81be8fddee4a8ac1d6da;createdFor; +584a81be8fddee4a8ac1ced9;584a81be8fddee4a8ac1ced8;584a81be8fddee4a8ac1ced0;createdFor; +584a81be8fddee4a8ac1f3a3;584a81be8fddee4a8ac1f3a2;584a81be8fddee4a8ac1d31e;createdFor; +584a81be8fddee4a8ac1d3e9;584a81be8fddee4a8ac1d3e8;584a81be8fddee4a8ac1d3e0;createdFor; +584a81be8fddee4a8ac1d3eb;584a81be8fddee4a8ac1d3ea;584a81be8fddee4a8ac1d3db;createdFor; +584a81be8fddee4a8ac1d221;584a81be8fddee4a8ac1d220;584a81be8fddee4a8ac1d218;createdFor; +584a81be8fddee4a8ac1d080;584a81be8fddee4a8ac1d07f;584a81be8fddee4a8ac1d070;createdFor; +584a81be8fddee4a8ac1d07e;584a81be8fddee4a8ac1d07d;584a81be8fddee4a8ac1d075;createdFor; +584a81be8fddee4a8ac1d3ff;584a81be8fddee4a8ac1d3fe;584a81be8fddee4a8ac1d3f6;createdFor; +584a81be8fddee4a8ac1d401;584a81be8fddee4a8ac1d400;584a81be8fddee4a8ac1d3f1;createdFor; +584a81be8fddee4a8ac1d2af;584a81be8fddee4a8ac1d2ae;584a81be8fddee4a8ac1d2a6;createdFor; +584a81be8fddee4a8ac1d78c;584a81be8fddee4a8ac1d78b;584a81be8fddee4a8ac1d783;createdFor; +584a81be8fddee4a8ac1d760;584a81be8fddee4a8ac1d75f;584a81be8fddee4a8ac1d757;createdFor; +584a81be8fddee4a8ac1d78e;584a81be8fddee4a8ac1d78d;584a81be8fddee4a8ac1d77e;createdFor; +584a81be8fddee4a8ac1d06a;584a81be8fddee4a8ac1d069;584a81be8fddee4a8ac1d05a;createdFor; +584a81be8fddee4a8ac1d068;584a81be8fddee4a8ac1d067;584a81be8fddee4a8ac1d05f;createdFor; +584a81be8fddee4a8ac1d2b1;584a81be8fddee4a8ac1d2b0;584a81be8fddee4a8ac1d2a1;createdFor; +584a81be8fddee4a8ac1cf4e;584a81be8fddee4a8ac1cf4d;584a81be8fddee4a8ac1cf3e;createdFor; +584a81be8fddee4a8ac1d415;584a81be8fddee4a8ac1d414;584a81be8fddee4a8ac1d40c;createdFor; +584a81be8fddee4a8ac1d417;584a81be8fddee4a8ac1d416;584a81be8fddee4a8ac1d407;createdFor; +584a81be8fddee4a8ac1fbf5;584a81be8fddee4a8ac1fbf4;584a81be8fddee4a8ac1d557;createdFor; +584a81be8fddee4a8ac1cf4c;584a81be8fddee4a8ac1cf4b;584a81be8fddee4a8ac1cf43;createdFor; +584a81be8fddee4a8ac1eeb5;584a81be8fddee4a8ac1eeb4;584a81be8fddee4a8ac1d1d1;createdFor; +584a81be8fddee4a8ac1d237;584a81be8fddee4a8ac1d236;584a81be8fddee4a8ac1d22e;createdFor; +584a81be8fddee4a8ac1d42d;584a81be8fddee4a8ac1d42c;584a81be8fddee4a8ac1d41d;createdFor; +584a81be8fddee4a8ac1d6d4;584a81be8fddee4a8ac1d6d3;584a81be8fddee4a8ac1d6c4;createdFor; +584a81be8fddee4a8ac1ebc5;584a81be8fddee4a8ac1ebc4;584a81be8fddee4a8ac1d0b7;createdFor; +584a81be8fddee4a8ac1d42b;584a81be8fddee4a8ac1d42a;584a81be8fddee4a8ac1d422;createdFor; +584a81be8fddee4a8ac1e7c9;584a81be8fddee4a8ac1e7c8;584a81be8fddee4a8ac1cf6f;createdFor; +584a81be8fddee4a8ac1d441;584a81be8fddee4a8ac1d440;584a81be8fddee4a8ac1d438;createdFor; +584a81be8fddee4a8ac1d443;584a81be8fddee4a8ac1d442;584a81be8fddee4a8ac1d433;createdFor; +584a81be8fddee4a8ac1d699;584a81be8fddee4a8ac1d698;584a81be8fddee4a8ac1d689;createdFor; +584a81be8fddee4a8ac1d697;584a81be8fddee4a8ac1d696;584a81be8fddee4a8ac1d68e;createdFor; +584a81be8fddee4a8ac1d457;584a81be8fddee4a8ac1d456;584a81be8fddee4a8ac1d44e;createdFor; +584a81be8fddee4a8ac1d459;584a81be8fddee4a8ac1d458;584a81be8fddee4a8ac1d449;createdFor; +584a81be8fddee4a8ac1d144;584a81be8fddee4a8ac1d143;584a81be8fddee4a8ac1d134;createdFor; +584a81be8fddee4a8ac1cf1b;584a81be8fddee4a8ac1cf1a;584a81be8fddee4a8ac1cf12;createdFor; +584a81be8fddee4a8ac1d04f;584a81be8fddee4a8ac1d04e;584a81be8fddee4a8ac1d03f;createdFor; +584a81be8fddee4a8ac1d04d;584a81be8fddee4a8ac1d04c;584a81be8fddee4a8ac1d044;createdFor; +584a81be8fddee4a8ac1d46d;584a81be8fddee4a8ac1d46c;584a81be8fddee4a8ac1d464;createdFor; +584a81be8fddee4a8ac1d46f;584a81be8fddee4a8ac1d46e;584a81be8fddee4a8ac1d45f;createdFor; +584a81be8fddee4a8ac1d683;584a81be8fddee4a8ac1d682;584a81be8fddee4a8ac1d673;createdFor; +584a81be8fddee4a8ac1d142;584a81be8fddee4a8ac1d141;584a81be8fddee4a8ac1d139;createdFor; +584a81be8fddee4a8ac1d6d2;584a81be8fddee4a8ac1d6d1;584a81be8fddee4a8ac1d6c9;createdFor; +584a81be8fddee4a8ac1d681;584a81be8fddee4a8ac1d680;584a81be8fddee4a8ac1d678;createdFor; +584a81be8fddee4a8ac1fbe9;584a81be8fddee4a8ac1fbe8;584a81be8fddee4a8ac1d552;createdFor; +584a81be8fddee4a8ac1cf1d;584a81be8fddee4a8ac1cf1c;584a81be8fddee4a8ac1cf0d;createdFor; +584a81be8fddee4a8ac1d039;584a81be8fddee4a8ac1d038;584a81be8fddee4a8ac1d029;createdFor; +584a81be8fddee4a8ac1d037;584a81be8fddee4a8ac1d036;584a81be8fddee4a8ac1d02e;createdFor; +584a81be8fddee4a8ac1d7a2;584a81be8fddee4a8ac1d7a1;584a81be8fddee4a8ac1d799;createdFor; +584a81be8fddee4a8ac1d48d;584a81be8fddee4a8ac1d48c;584a81be8fddee4a8ac1d484;createdFor; +584a81be8fddee4a8ac1d48f;584a81be8fddee4a8ac1d48e;584a81be8fddee4a8ac1d47f;createdFor; +584a81be8fddee4a8ac1d2c5;584a81be8fddee4a8ac1d2c4;584a81be8fddee4a8ac1d2bc;createdFor; +584a81be8fddee4a8ac1d7a4;584a81be8fddee4a8ac1d7a3;584a81be8fddee4a8ac1d794;createdFor; +584a81be8fddee4a8ac1d01e;584a81be8fddee4a8ac1d01d;584a81be8fddee4a8ac1d00e;createdFor; +584a81be8fddee4a8ac1d2c7;584a81be8fddee4a8ac1d2c6;584a81be8fddee4a8ac1d2b7;createdFor; +584a81be8fddee4a8ac1d01c;584a81be8fddee4a8ac1d01b;584a81be8fddee4a8ac1d013;createdFor; +584a81be8fddee4a8ac1e833;584a81be8fddee4a8ac1e832;584a81be8fddee4a8ac1cf8a;createdFor; +584a81be8fddee4a8ac1d24d;584a81be8fddee4a8ac1d24c;584a81be8fddee4a8ac1d244;createdFor; +584a81be8fddee4a8ac1d4a3;584a81be8fddee4a8ac1d4a2;584a81be8fddee4a8ac1d49a;createdFor; +584a81be8fddee4a8ac1d4a5;584a81be8fddee4a8ac1d4a4;584a81be8fddee4a8ac1d495;createdFor; +584a81be8fddee4a8ac1ceaa;584a81be8fddee4a8ac1cea9;584a81be8fddee4a8ac1ce9a;createdFor; +584a81be8fddee4a8ac1d6fe;584a81be8fddee4a8ac1d6fd;584a81be8fddee4a8ac1d6f5;createdFor; +584a81be8fddee4a8ac1d745;584a81be8fddee4a8ac1d744;584a81be8fddee4a8ac1d73c;createdFor; +584a81be8fddee4a8ac1d66b;584a81be8fddee4a8ac1d66a;584a81be8fddee4a8ac1d662;createdFor; +584a81be8fddee4a8ac1d008;584a81be8fddee4a8ac1d007;584a81be8fddee4a8ac1cff8;createdFor; +584a81be8fddee4a8ac1d006;584a81be8fddee4a8ac1d005;584a81be8fddee4a8ac1cffd;createdFor; +584a81be8fddee4a8ac1eb7a;584a81be8fddee4a8ac1eb79;584a81be8fddee4a8ac1d0a1;createdFor; +584a81be8fddee4a8ac1d700;584a81be8fddee4a8ac1d6ff;584a81be8fddee4a8ac1d6f0;createdFor; +584a81be8fddee4a8ac1cea8;584a81be8fddee4a8ac1cea7;584a81be8fddee4a8ac1ce9f;createdFor; +584a81be8fddee4a8ac1d66d;584a81be8fddee4a8ac1d66c;584a81be8fddee4a8ac1d65d;createdFor; +584a81be8fddee4a8ac1d731;584a81be8fddee4a8ac1d730;584a81be8fddee4a8ac1d721;createdFor; +584a81be8fddee4a8ac1eb78;584a81be8fddee4a8ac1eb77;584a81be8fddee4a8ac1d09c;createdFor; +584a81be8fddee4a8ac1d4c8;584a81be8fddee4a8ac1d4c7;584a81be8fddee4a8ac1d4bf;createdFor; +584a81be8fddee4a8ac1d4ca;584a81be8fddee4a8ac1d4c9;584a81be8fddee4a8ac1d4ba;createdFor; +584a81be8fddee4a8ac1d263;584a81be8fddee4a8ac1d262;584a81be8fddee4a8ac1d25a;createdFor; +584a81be8fddee4a8ac1cff2;584a81be8fddee4a8ac1cff1;584a81be8fddee4a8ac1cfe2;createdFor; +584a81be8fddee4a8ac1d7b8;584a81be8fddee4a8ac1d7b7;584a81be8fddee4a8ac1d7af;createdFor; +584a81be8fddee4a8ac1cff0;584a81be8fddee4a8ac1cfef;584a81be8fddee4a8ac1cfe7;createdFor; +584a81be8fddee4a8ac1d20b;584a81be8fddee4a8ac1d20a;584a81be8fddee4a8ac1d202;createdFor; +584a81be8fddee4a8ac1d7ba;584a81be8fddee4a8ac1d7b9;584a81be8fddee4a8ac1d7aa;createdFor; +584a81be8fddee4a8ac1cf31;584a81be8fddee4a8ac1cf30;584a81be8fddee4a8ac1cf28;createdFor; +584a81be8fddee4a8ac1d657;584a81be8fddee4a8ac1d656;584a81be8fddee4a8ac1d647;createdFor; +584a81be8fddee4a8ac1d655;584a81be8fddee4a8ac1d654;584a81be8fddee4a8ac1d64c;createdFor; +584a81be8fddee4a8ac1d2db;584a81be8fddee4a8ac1d2da;584a81be8fddee4a8ac1d2d2;createdFor; +584a81be8fddee4a8ac1fca1;584a81be8fddee4a8ac1fca0;584a81be8fddee4a8ac1d5be;createdFor; +584a81be8fddee4a8ac1d2dd;584a81be8fddee4a8ac1d2dc;584a81be8fddee4a8ac1d2cd;createdFor; +584a81be8fddee4a8ac1d4f2;584a81be8fddee4a8ac1d4f1;584a81be8fddee4a8ac1d4e9;createdFor; +584a81be8fddee4a8ac1d4f4;584a81be8fddee4a8ac1d4f3;584a81be8fddee4a8ac1d4e4;createdFor; +584a81be8fddee4a8ac1cfdc;584a81be8fddee4a8ac1cfdb;584a81be8fddee4a8ac1cfcc;createdFor; +584a81be8fddee4a8ac1cfda;584a81be8fddee4a8ac1cfd9;584a81be8fddee4a8ac1cfd1;createdFor; +584a81be8fddee4a8ac1cf33;584a81be8fddee4a8ac1cf32;584a81be8fddee4a8ac1cf23;createdFor; +584a81be8fddee4a8ac1d265;584a81be8fddee4a8ac1d264;584a81be8fddee4a8ac1d255;createdFor; +584a81be8fddee4a8ac1d508;584a81be8fddee4a8ac1d507;584a81be8fddee4a8ac1d4ff;createdFor; +584a81be8fddee4a8ac1d50a;584a81be8fddee4a8ac1d509;584a81be8fddee4a8ac1d4fa;createdFor; +584a81be8fddee4a8ac1d72f;584a81be8fddee4a8ac1d72e;584a81be8fddee4a8ac1d726;createdFor; +584a81be8fddee4a8ac1d24f;584a81be8fddee4a8ac1d24e;584a81be8fddee4a8ac1d23f;createdFor; +584a81be8fddee4a8ac1cfc6;584a81be8fddee4a8ac1cfc5;584a81be8fddee4a8ac1cfb6;createdFor; +584a81be8fddee4a8ac1ebbf;584a81be8fddee4a8ac1ebb3;584a81be8fddee4a8ac1ebbd;openedBy; +584a81be8fddee4a8ac1ecef;584a81be8fddee4a8ac1ecd6;584a81be8fddee4a8ac1eced;openedBy; +584a81be8fddee4a8ac1e8b6;584a81be8fddee4a8ac1e8a6;584a81be8fddee4a8ac1e8b4;openedBy; +584a81be8fddee4a8ac1fded;584a81be8fddee4a8ac1fde0;584a81be8fddee4a8ac1fdeb;openedBy; +584a81be8fddee4a8ac1eea9;584a81be8fddee4a8ac1ee8d;584a81be8fddee4a8ac1eea6;openedBy; +584a81be8fddee4a8ac1eb76;584a81be8fddee4a8ac1eb52;584a81be8fddee4a8ac1eb74;openedBy; +584a81be8fddee4a8ac1fc9b;584a81be8fddee4a8ac1fc8e;584a81be8fddee4a8ac1fc99;openedBy; +584a81be8fddee4a8ac1f036;584a81be8fddee4a8ac1f019;584a81be8fddee4a8ac1f033;openedBy; +584a81be8fddee4a8ac1ea4a;584a81be8fddee4a8ac1ea2f;584a81be8fddee4a8ac1ea47;openedBy; +584a81be8fddee4a8ac1f38e;584a81be8fddee4a8ac1f370;584a81be8fddee4a8ac1f38c;openedBy; +584a81be8fddee4a8ac1e7c5;584a81be8fddee4a8ac1e7b3;584a81be8fddee4a8ac1e7c3;openedBy; +584a81be8fddee4a8ac1e824;584a81be8fddee4a8ac1e815;584a81be8fddee4a8ac1e822;openedBy; +584a81be8fddee4a8ac1e458;584a81be8fddee4a8ac1e43d;584a81be8fddee4a8ac1e456;openedBy; +584a81be8fddee4a8ac1fda2;584a81be8fddee4a8ac1fd96;584a81be8fddee4a8ac1fda0;openedBy; +584a81be8fddee4a8ac1ee04;584a81be8fddee4a8ac1ede6;584a81be8fddee4a8ac1ee01;openedBy; +584a81be8fddee4a8ac1e8cb;584a81be8fddee4a8ac1e8c5;584a81be8fddee4a8ac1e8b4;openedBy; +584a81be8fddee4a8ac1fbd9;584a81be8fddee4a8ac1fbc4;584a81be8fddee4a8ac1fbd7;openedBy; +584a81be8fddee4a8ac1f64e;584a81be8fddee4a8ac1f62a;584a81be8fddee4a8ac1f64c;openedBy; +584a81be8fddee4a8ac1d297;584a81be8fddee4a8ac1d295;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d6fc;584a81be8fddee4a8ac1d6fa;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d3bb;584a81be8fddee4a8ac1d3b9;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d0c3;584a81be8fddee4a8ac1d0c1;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d035;584a81be8fddee4a8ac1d033;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d46b;584a81be8fddee4a8ac1d469;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d6b0;584a81be8fddee4a8ac1d6ae;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d67f;584a81be8fddee4a8ac1d67d;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cebc;584a81be8fddee4a8ac1ceba;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d092;584a81be8fddee4a8ac1d090;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cfd8;584a81be8fddee4a8ac1cfd6;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d180;584a81be8fddee4a8ac1d17e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d2c3;584a81be8fddee4a8ac1d2c1;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d653;584a81be8fddee4a8ac1d651;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d3d1;584a81be8fddee4a8ac1d3cf;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d48b;584a81be8fddee4a8ac1d489;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d0a8;584a81be8fddee4a8ac1d0a6;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d743;584a81be8fddee4a8ac1d741;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf60;584a81be8fddee4a8ac1cf5e;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d32a;584a81be8fddee4a8ac1d328;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d2d9;584a81be8fddee4a8ac1d2d7;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d7cc;584a81be8fddee4a8ac1d7ca;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d2ef;584a81be8fddee4a8ac1d2ed;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d3e7;584a81be8fddee4a8ac1d3e5;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d55e;584a81be8fddee4a8ac1d55c;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d75e;584a81be8fddee4a8ac1d75c;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d695;584a81be8fddee4a8ac1d693;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cfa7;584a81be8fddee4a8ac1cfa5;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d01a;584a81be8fddee4a8ac1d018;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d4a1;584a81be8fddee4a8ac1d49f;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d1b1;584a81be8fddee4a8ac1d1af;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cfc2;584a81be8fddee4a8ac1cfc0;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d579;584a81be8fddee4a8ac1d577;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d72d;584a81be8fddee4a8ac1d72b;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d3fd;584a81be8fddee4a8ac1d3fb;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d16a;584a81be8fddee4a8ac1d168;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d07c;584a81be8fddee4a8ac1d07a;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf91;584a81be8fddee4a8ac1cf8f;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cf91;584a81be8fddee4a8ac1cf8f;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d10a;584a81be8fddee4a8ac1d108;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d140;584a81be8fddee4a8ac1d13e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1ced7;584a81be8fddee4a8ac1ced5;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d58f;584a81be8fddee4a8ac1d58d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d627;584a81be8fddee4a8ac1d625;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf76;584a81be8fddee4a8ac1cf74;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d67f;584a81be8fddee4a8ac1d67d;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d1dd;584a81be8fddee4a8ac1d1db;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d5a5;584a81be8fddee4a8ac1d5a3;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d035;584a81be8fddee4a8ac1d033;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d506;584a81be8fddee4a8ac1d504;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf76;584a81be8fddee4a8ac1cf74;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d7e2;584a81be8fddee4a8ac1d7e0;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d21f;584a81be8fddee4a8ac1d21d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d611;584a81be8fddee4a8ac1d60f;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d413;584a81be8fddee4a8ac1d411;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf2f;584a81be8fddee4a8ac1cf2d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cfc2;584a81be8fddee4a8ac1cfc0;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d066;584a81be8fddee4a8ac1d064;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d196;584a81be8fddee4a8ac1d194;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d5ca;584a81be8fddee4a8ac1d5c8;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d78a;584a81be8fddee4a8ac1d788;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cfee;584a81be8fddee4a8ac1cfec;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d004;584a81be8fddee4a8ac1d002;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d30f;584a81be8fddee4a8ac1d30d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d2ad;584a81be8fddee4a8ac1d2ab;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d5e5;584a81be8fddee4a8ac1d5e3;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d7fd;584a81be8fddee4a8ac1d7fb;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d548;584a81be8fddee4a8ac1d546;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d429;584a81be8fddee4a8ac1d427;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d12a;584a81be8fddee4a8ac1d128;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d5fb;584a81be8fddee4a8ac1d5f9;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d669;584a81be8fddee4a8ac1d667;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d5ca;584a81be8fddee4a8ac1d5c8;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d1f3;584a81be8fddee4a8ac1d1f1;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d0f4;584a81be8fddee4a8ac1d0f2;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d43f;584a81be8fddee4a8ac1d43d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1ceed;584a81be8fddee4a8ac1ceeb;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d297;584a81be8fddee4a8ac1d295;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d63d;584a81be8fddee4a8ac1d63b;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1cf2f;584a81be8fddee4a8ac1cf2d;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d32a;584a81be8fddee4a8ac1d328;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d281;584a81be8fddee4a8ac1d27f;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d340;584a81be8fddee4a8ac1d33e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d140;584a81be8fddee4a8ac1d13e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cf4a;584a81be8fddee4a8ac1cf48;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d04b;584a81be8fddee4a8ac1d049;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d35b;584a81be8fddee4a8ac1d359;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d235;584a81be8fddee4a8ac1d233;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cf19;584a81be8fddee4a8ac1cf17;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d0de;584a81be8fddee4a8ac1d0dc;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d455;584a81be8fddee4a8ac1d453;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d24b;584a81be8fddee4a8ac1d249;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d695;584a81be8fddee4a8ac1d693;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d1c7;584a81be8fddee4a8ac1d1c5;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d1dd;584a81be8fddee4a8ac1d1db;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d7a0;584a81be8fddee4a8ac1d79e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d37b;584a81be8fddee4a8ac1d379;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d209;584a81be8fddee4a8ac1d207;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d4f0;584a81be8fddee4a8ac1d4ee;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d6d0;584a81be8fddee4a8ac1d6ce;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d1b1;584a81be8fddee4a8ac1d1af;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d261;584a81be8fddee4a8ac1d25f;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cf03;584a81be8fddee4a8ac1cf01;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d0c3;584a81be8fddee4a8ac1d0c1;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d51c;584a81be8fddee4a8ac1d51a;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d4c6;584a81be8fddee4a8ac1d4c4;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d717;584a81be8fddee4a8ac1d715;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d774;584a81be8fddee4a8ac1d772;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d55e;584a81be8fddee4a8ac1d55c;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d6e6;584a81be8fddee4a8ac1d6e4;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d532;584a81be8fddee4a8ac1d530;584a81be8fddee4a8ac1cd94;operatedBy; +584a81be8fddee4a8ac1d7b6;584a81be8fddee4a8ac1d7b4;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d3a0;584a81be8fddee4a8ac1d39e;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d0a8;584a81be8fddee4a8ac1d0a6;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d46b;584a81be8fddee4a8ac1d469;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1cea6;584a81be8fddee4a8ac1cea4;584a81be8fddee4a8ac1cd92;operatedBy; +584a81be8fddee4a8ac1d356;584a81be8fddee4a8ac1d354;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cf5b;584a81be8fddee4a8ac1cf59;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d5e0;584a81be8fddee4a8ac1d5de;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d466;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d0d9;584a81be8fddee4a8ac1d0d7;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d501;584a81be8fddee4a8ac1d4ff;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d5f6;584a81be8fddee4a8ac1d5f4;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d125;584a81be8fddee4a8ac1d123;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d25c;584a81be8fddee4a8ac1d25a;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d030;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cf45;584a81be8fddee4a8ac1cf43;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d105;584a81be8fddee4a8ac1d103;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1cee8;584a81be8fddee4a8ac1cee6;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d690;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d061;584a81be8fddee4a8ac1d05f;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d73e;584a81be8fddee4a8ac1d73c;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d13b;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d79b;584a81be8fddee4a8ac1d799;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d30a;584a81be8fddee4a8ac1d308;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d424;584a81be8fddee4a8ac1d422;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1ceb7;584a81be8fddee4a8ac1ceb5;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d450;584a81be8fddee4a8ac1d44e;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d543;584a81be8fddee4a8ac1d541;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d13b;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d664;584a81be8fddee4a8ac1d662;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cfbd;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d292;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d6ab;584a81be8fddee4a8ac1d6a9;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d486;584a81be8fddee4a8ac1d484;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d466;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1ced2;584a81be8fddee4a8ac1ced0;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d3e2;584a81be8fddee4a8ac1d3e0;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cf71;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d325;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d030;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d622;584a81be8fddee4a8ac1d620;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d517;584a81be8fddee4a8ac1d515;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d230;584a81be8fddee4a8ac1d22e;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d690;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d728;584a81be8fddee4a8ac1d726;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d7c7;584a81be8fddee4a8ac1d7c5;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cf8c;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1cefe;584a81be8fddee4a8ac1cefc;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d6e1;584a81be8fddee4a8ac1d6df;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d17b;584a81be8fddee4a8ac1d179;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d574;584a81be8fddee4a8ac1d572;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cfd3;584a81be8fddee4a8ac1cfd1;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d67a;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cf8c;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d1d8;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d2ea;584a81be8fddee4a8ac1d2e8;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d0a3;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cfbd;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d785;584a81be8fddee4a8ac1d783;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d0ef;584a81be8fddee4a8ac1d0ed;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cfa2;584a81be8fddee4a8ac1cfa0;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d1ac;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d33b;584a81be8fddee4a8ac1d339;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d638;584a81be8fddee4a8ac1d636;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d3f8;584a81be8fddee4a8ac1d3f6;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d046;584a81be8fddee4a8ac1d044;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d077;584a81be8fddee4a8ac1d075;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d52d;584a81be8fddee4a8ac1d52b;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d246;584a81be8fddee4a8ac1d244;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d58a;584a81be8fddee4a8ac1d588;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d39b;584a81be8fddee4a8ac1d399;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d7dd;584a81be8fddee4a8ac1d7db;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cea1;584a81be8fddee4a8ac1ce9f;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1cfff;584a81be8fddee4a8ac1cffd;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d1ee;584a81be8fddee4a8ac1d1ec;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d21a;584a81be8fddee4a8ac1d218;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d2d4;584a81be8fddee4a8ac1d2d2;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d2be;584a81be8fddee4a8ac1d2bc;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d5c5;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d559;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d27c;584a81be8fddee4a8ac1d27a;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d5a0;584a81be8fddee4a8ac1d59e;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d49c;584a81be8fddee4a8ac1d49a;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1cfe9;584a81be8fddee4a8ac1cfe7;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d43a;584a81be8fddee4a8ac1d438;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d60c;584a81be8fddee4a8ac1d60a;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d1c2;584a81be8fddee4a8ac1d1c0;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d3b6;584a81be8fddee4a8ac1d3b4;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d191;584a81be8fddee4a8ac1d18f;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cf2a;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1cf71;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d1ac;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cf2a;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d015;584a81be8fddee4a8ac1d013;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d76f;584a81be8fddee4a8ac1d76d;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d712;584a81be8fddee4a8ac1d710;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d7b1;584a81be8fddee4a8ac1d7af;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d08d;584a81be8fddee4a8ac1d08b;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d7f8;584a81be8fddee4a8ac1d7f6;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d165;584a81be8fddee4a8ac1d163;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d40e;584a81be8fddee4a8ac1d40c;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d5c5;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d376;584a81be8fddee4a8ac1d374;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d4eb;584a81be8fddee4a8ac1d4e9;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1cf14;584a81be8fddee4a8ac1cf12;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d67a;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d64e;584a81be8fddee4a8ac1d64c;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d0be;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d559;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d204;584a81be8fddee4a8ac1d202;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d1d8;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d6f7;584a81be8fddee4a8ac1d6f5;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d2a8;584a81be8fddee4a8ac1d2a6;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d0a3;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d759;584a81be8fddee4a8ac1d757;584a81be8fddee4a8ac1cdce;placedAt; +584a81be8fddee4a8ac1d6cb;584a81be8fddee4a8ac1d6c9;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d325;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d4c1;584a81be8fddee4a8ac1d4bf;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d292;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1cdcd;placedAt; +584a81be8fddee4a8ac1d3cc;584a81be8fddee4a8ac1d3ca;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d0be;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1cdcc;placedAt; +584a81be8fddee4a8ac1d000;584a81be8fddee4a8ac1cffd;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1ced3;584a81be8fddee4a8ac1ced0;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d176;584a81be8fddee4a8ac1d174;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d241;584a81be8fddee4a8ac1d23f;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d247;584a81be8fddee4a8ac1d244;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d17c;584a81be8fddee4a8ac1d179;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d25d;584a81be8fddee4a8ac1d25a;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d257;584a81be8fddee4a8ac1d255;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d6c6;584a81be8fddee4a8ac1d6c4;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d160;584a81be8fddee4a8ac1d15e;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d166;584a81be8fddee4a8ac1d163;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d27d;584a81be8fddee4a8ac1d27a;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d277;584a81be8fddee4a8ac1d275;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cee3;584a81be8fddee4a8ac1cee1;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d28d;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d293;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cee9;584a81be8fddee4a8ac1cee6;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d2a3;584a81be8fddee4a8ac1d2a1;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d2a9;584a81be8fddee4a8ac1d2a6;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cecd;584a81be8fddee4a8ac1cecb;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d136;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d73f;584a81be8fddee4a8ac1d73c;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d2b9;584a81be8fddee4a8ac1d2b7;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d2bf;584a81be8fddee4a8ac1d2bc;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d13c;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d754;584a81be8fddee4a8ac1d752;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d2cf;584a81be8fddee4a8ac1d2cd;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d2d5;584a81be8fddee4a8ac1d2d2;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d120;584a81be8fddee4a8ac1d11e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d126;584a81be8fddee4a8ac1d123;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d2eb;584a81be8fddee4a8ac1d2e8;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d2e5;584a81be8fddee4a8ac1d2e3;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1ceb8;584a81be8fddee4a8ac1ceb5;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d100;584a81be8fddee4a8ac1d0fe;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d106;584a81be8fddee4a8ac1d103;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d30b;584a81be8fddee4a8ac1d308;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d305;584a81be8fddee4a8ac1d303;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d0f0;584a81be8fddee4a8ac1d0ed;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d0ea;584a81be8fddee4a8ac1d0e8;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1ceb2;584a81be8fddee4a8ac1ceb0;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d326;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d320;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d6e2;584a81be8fddee4a8ac1d6df;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d0d4;584a81be8fddee4a8ac1d0d2;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d33c;584a81be8fddee4a8ac1d339;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d336;584a81be8fddee4a8ac1d334;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cef9;584a81be8fddee4a8ac1cef7;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d0da;584a81be8fddee4a8ac1d0d7;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d351;584a81be8fddee4a8ac1d34f;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d357;584a81be8fddee4a8ac1d354;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1ceff;584a81be8fddee4a8ac1cefc;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d371;584a81be8fddee4a8ac1d36f;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d377;584a81be8fddee4a8ac1d374;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d6dc;584a81be8fddee4a8ac1d6da;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d0bf;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d0b9;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d39c;584a81be8fddee4a8ac1d399;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d09e;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d396;584a81be8fddee4a8ac1d394;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d0a4;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d3b1;584a81be8fddee4a8ac1d3af;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d3b7;584a81be8fddee4a8ac1d3b4;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d088;584a81be8fddee4a8ac1d086;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d3cd;584a81be8fddee4a8ac1d3ca;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d3c7;584a81be8fddee4a8ac1d3c5;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d08e;584a81be8fddee4a8ac1d08b;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d3e3;584a81be8fddee4a8ac1d3e0;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d078;584a81be8fddee4a8ac1d075;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d3dd;584a81be8fddee4a8ac1d3db;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d739;584a81be8fddee4a8ac1d737;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d072;584a81be8fddee4a8ac1d070;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d3f3;584a81be8fddee4a8ac1d3f1;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d3f9;584a81be8fddee4a8ac1d3f6;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d409;584a81be8fddee4a8ac1d407;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d40f;584a81be8fddee4a8ac1d40c;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d05c;584a81be8fddee4a8ac1d05a;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cf0f;584a81be8fddee4a8ac1cf0d;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d062;584a81be8fddee4a8ac1d05f;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d425;584a81be8fddee4a8ac1d422;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d41f;584a81be8fddee4a8ac1d41d;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d43b;584a81be8fddee4a8ac1d438;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d435;584a81be8fddee4a8ac1d433;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d047;584a81be8fddee4a8ac1d044;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d44b;584a81be8fddee4a8ac1d449;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d451;584a81be8fddee4a8ac1d44e;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d041;584a81be8fddee4a8ac1d03f;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d75a;584a81be8fddee4a8ac1d757;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d461;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d467;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d031;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d02b;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d016;584a81be8fddee4a8ac1d013;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d481;584a81be8fddee4a8ac1d47f;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d487;584a81be8fddee4a8ac1d484;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cf15;584a81be8fddee4a8ac1cf12;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d010;584a81be8fddee4a8ac1d00e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d49d;584a81be8fddee4a8ac1d49a;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d497;584a81be8fddee4a8ac1d495;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d6f2;584a81be8fddee4a8ac1d6f0;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cffa;584a81be8fddee4a8ac1cff8;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d4c2;584a81be8fddee4a8ac1d4bf;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d4bc;584a81be8fddee4a8ac1d4ba;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cfe4;584a81be8fddee4a8ac1cfe2;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cf2b;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cfea;584a81be8fddee4a8ac1cfe7;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d6f8;584a81be8fddee4a8ac1d6f5;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d4ec;584a81be8fddee4a8ac1d4e9;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cfd4;584a81be8fddee4a8ac1cfd1;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d4e6;584a81be8fddee4a8ac1d4e4;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cfce;584a81be8fddee4a8ac1cfcc;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d502;584a81be8fddee4a8ac1d4ff;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d4fc;584a81be8fddee4a8ac1d4fa;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cfb8;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d512;584a81be8fddee4a8ac1d510;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d518;584a81be8fddee4a8ac1d515;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cf25;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cfbe;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d70d;584a81be8fddee4a8ac1d70b;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d52e;584a81be8fddee4a8ac1d52b;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d528;584a81be8fddee4a8ac1d526;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1ce9c;584a81be8fddee4a8ac1ce9a;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d544;584a81be8fddee4a8ac1d541;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d53e;584a81be8fddee4a8ac1d53c;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cea2;584a81be8fddee4a8ac1ce9f;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d55a;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d554;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cf9d;584a81be8fddee4a8ac1cf9b;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d56f;584a81be8fddee4a8ac1d56d;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cfa3;584a81be8fddee4a8ac1cfa0;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d575;584a81be8fddee4a8ac1d572;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cf87;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d58b;584a81be8fddee4a8ac1d588;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d585;584a81be8fddee4a8ac1d583;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cf8d;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d59b;584a81be8fddee4a8ac1d599;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d5a1;584a81be8fddee4a8ac1d59e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cf72;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d713;584a81be8fddee4a8ac1d710;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cf6c;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cf56;584a81be8fddee4a8ac1cf54;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d7f9;584a81be8fddee4a8ac1d7f6;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7f3;584a81be8fddee4a8ac1d7f1;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d5c6;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d5c0;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d5db;584a81be8fddee4a8ac1d5d9;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d5e1;584a81be8fddee4a8ac1d5de;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7d8;584a81be8fddee4a8ac1d7d6;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d5f1;584a81be8fddee4a8ac1d5ef;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d5f7;584a81be8fddee4a8ac1d5f4;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7de;584a81be8fddee4a8ac1d7db;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d60d;584a81be8fddee4a8ac1d60a;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d607;584a81be8fddee4a8ac1d605;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d623;584a81be8fddee4a8ac1d620;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d61d;584a81be8fddee4a8ac1d61b;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d7c8;584a81be8fddee4a8ac1d7c5;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7c2;584a81be8fddee4a8ac1d7c0;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d633;584a81be8fddee4a8ac1d631;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d639;584a81be8fddee4a8ac1d636;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7b2;584a81be8fddee4a8ac1d7af;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d649;584a81be8fddee4a8ac1d647;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d64f;584a81be8fddee4a8ac1d64c;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d7ac;584a81be8fddee4a8ac1d7aa;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d665;584a81be8fddee4a8ac1d662;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d65f;584a81be8fddee4a8ac1d65d;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1cf5c;584a81be8fddee4a8ac1cf59;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d796;584a81be8fddee4a8ac1d794;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d67b;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d675;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d723;584a81be8fddee4a8ac1d721;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d79c;584a81be8fddee4a8ac1d799;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d68b;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d691;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d780;584a81be8fddee4a8ac1d77e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d786;584a81be8fddee4a8ac1d783;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d729;584a81be8fddee4a8ac1d726;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d6ac;584a81be8fddee4a8ac1d6a9;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d6a6;584a81be8fddee4a8ac1d6a4;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1cf46;584a81be8fddee4a8ac1cf43;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d770;584a81be8fddee4a8ac1d76d;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1cf40;584a81be8fddee4a8ac1cf3e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d1d3;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d1d9;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d1bd;584a81be8fddee4a8ac1d1bb;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d1c3;584a81be8fddee4a8ac1d1c0;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d1e9;584a81be8fddee4a8ac1d1e7;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d1ef;584a81be8fddee4a8ac1d1ec;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d1a7;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d76a;584a81be8fddee4a8ac1d768;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d205;584a81be8fddee4a8ac1d202;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d1ff;584a81be8fddee4a8ac1d1fd;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d1ad;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d21b;584a81be8fddee4a8ac1d218;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d192;584a81be8fddee4a8ac1d18f;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d6cc;584a81be8fddee4a8ac1d6c9;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d215;584a81be8fddee4a8ac1d213;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d22b;584a81be8fddee4a8ac1d229;584a81be8fddee4a8ac1cdbe;processedBy; +584a81be8fddee4a8ac1d231;584a81be8fddee4a8ac1d22e;584a81be8fddee4a8ac1cdc0;processedBy; +584a81be8fddee4a8ac1d18c;584a81be8fddee4a8ac1d18a;584a81be8fddee4a8ac1cdbb;processedBy; +584a81be8fddee4a8ac1d7c1;584a81be8fddee4a8ac1d7c0;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d11f;584a81be8fddee4a8ac1d11e;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d753;584a81be8fddee4a8ac1d752;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cfcd;584a81be8fddee4a8ac1cfcc;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d1d2;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d4fb;584a81be8fddee4a8ac1d4fa;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d4e5;584a81be8fddee4a8ac1d4e4;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cfe3;584a81be8fddee4a8ac1cfe2;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d09d;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d648;584a81be8fddee4a8ac1d647;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cf3f;584a81be8fddee4a8ac1cf3e;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d2ce;584a81be8fddee4a8ac1d2cd;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cff9;584a81be8fddee4a8ac1cff8;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d4bb;584a81be8fddee4a8ac1d4ba;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d7ab;584a81be8fddee4a8ac1d7aa;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cfb7;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d175;584a81be8fddee4a8ac1d174;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d22a;584a81be8fddee4a8ac1d229;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d00f;584a81be8fddee4a8ac1d00e;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cf0e;584a81be8fddee4a8ac1cf0d;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d496;584a81be8fddee4a8ac1d495;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d65e;584a81be8fddee4a8ac1d65d;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d480;584a81be8fddee4a8ac1d47f;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d5bf;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1ceb1;584a81be8fddee4a8ac1ceb0;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d135;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d460;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d0b8;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d02a;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d674;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1cf6b;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cecc;584a81be8fddee4a8ac1cecb;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d44a;584a81be8fddee4a8ac1d449;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d18b;584a81be8fddee4a8ac1d18a;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d2b8;584a81be8fddee4a8ac1d2b7;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d1fe;584a81be8fddee4a8ac1d1fd;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d040;584a81be8fddee4a8ac1d03f;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d434;584a81be8fddee4a8ac1d433;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d41e;584a81be8fddee4a8ac1d41d;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d795;584a81be8fddee4a8ac1d794;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d05b;584a81be8fddee4a8ac1d05a;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d408;584a81be8fddee4a8ac1d407;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d2a2;584a81be8fddee4a8ac1d2a1;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d68a;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d071;584a81be8fddee4a8ac1d070;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d3f2;584a81be8fddee4a8ac1d3f1;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d6a5;584a81be8fddee4a8ac1d6a4;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d135;584a81be8fddee4a8ac1d134;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d3dc;584a81be8fddee4a8ac1d3db;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d77f;584a81be8fddee4a8ac1d77e;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d6f1;584a81be8fddee4a8ac1d6f0;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d769;584a81be8fddee4a8ac1d768;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d087;584a81be8fddee4a8ac1d086;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cef8;584a81be8fddee4a8ac1cef7;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d3c6;584a81be8fddee4a8ac1d3c5;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d3b0;584a81be8fddee4a8ac1d3af;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d09d;584a81be8fddee4a8ac1d09c;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d674;584a81be8fddee4a8ac1d673;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1cf86;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d553;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d240;584a81be8fddee4a8ac1d23f;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d395;584a81be8fddee4a8ac1d394;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d28c;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d68a;584a81be8fddee4a8ac1d689;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d6c5;584a81be8fddee4a8ac1d6c4;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d370;584a81be8fddee4a8ac1d36f;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d0b8;584a81be8fddee4a8ac1d0b7;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d1bc;584a81be8fddee4a8ac1d1bb;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d0d3;584a81be8fddee4a8ac1d0d2;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d350;584a81be8fddee4a8ac1d34f;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d1a6;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d0e9;584a81be8fddee4a8ac1d0e8;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d28c;584a81be8fddee4a8ac1d28b;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d1d2;584a81be8fddee4a8ac1d1d1;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d335;584a81be8fddee4a8ac1d334;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d214;584a81be8fddee4a8ac1d213;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d31f;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d15f;584a81be8fddee4a8ac1d15e;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d31f;584a81be8fddee4a8ac1d31e;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d276;584a81be8fddee4a8ac1d275;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d6db;584a81be8fddee4a8ac1d6da;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d0ff;584a81be8fddee4a8ac1d0fe;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d5f0;584a81be8fddee4a8ac1d5ef;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d5da;584a81be8fddee4a8ac1d5d9;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d738;584a81be8fddee4a8ac1d737;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d70c;584a81be8fddee4a8ac1d70b;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d304;584a81be8fddee4a8ac1d303;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d7f2;584a81be8fddee4a8ac1d7f1;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d5bf;584a81be8fddee4a8ac1d5be;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cf24;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d1a6;584a81be8fddee4a8ac1d1a5;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1cf6b;584a81be8fddee4a8ac1cf6a;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d59a;584a81be8fddee4a8ac1d599;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d606;584a81be8fddee4a8ac1d605;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d7d7;584a81be8fddee4a8ac1d7d6;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1ce9b;584a81be8fddee4a8ac1ce9a;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d722;584a81be8fddee4a8ac1d721;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d584;584a81be8fddee4a8ac1d583;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cee2;584a81be8fddee4a8ac1cee1;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d460;584a81be8fddee4a8ac1d45f;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cf24;584a81be8fddee4a8ac1cf23;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1cf86;584a81be8fddee4a8ac1cf85;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d56e;584a81be8fddee4a8ac1d56d;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d02a;584a81be8fddee4a8ac1d029;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1cf9c;584a81be8fddee4a8ac1cf9b;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d553;584a81be8fddee4a8ac1d552;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d1e8;584a81be8fddee4a8ac1d1e7;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d2e4;584a81be8fddee4a8ac1d2e3;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d61c;584a81be8fddee4a8ac1d61b;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d53d;584a81be8fddee4a8ac1d53c;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cfb7;584a81be8fddee4a8ac1cfb6;584a81be8fddee4a8ac1cd93;receivedFrom; +584a81be8fddee4a8ac1d256;584a81be8fddee4a8ac1d255;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d632;584a81be8fddee4a8ac1d631;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1d527;584a81be8fddee4a8ac1d526;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1cf55;584a81be8fddee4a8ac1cf54;584a81be8fddee4a8ac1cd95;receivedFrom; +584a81be8fddee4a8ac1d511;584a81be8fddee4a8ac1d510;584a81be8fddee4a8ac1cd96;receivedFrom; +584a81be8fddee4a8ac1e81f;584a81be8fddee4a8ac1e81e;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1eb75;584a81be8fddee4a8ac1eb74;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1e44b;584a81be8fddee4a8ac1e449;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1f648;584a81be8fddee4a8ac1f647;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1f034;584a81be8fddee4a8ac1f033;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1fd99;584a81be8fddee4a8ac1fd98;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1f641;584a81be8fddee4a8ac1f640;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1ee03;584a81be8fddee4a8ac1ee01;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1ea3b;584a81be8fddee4a8ac1ea39;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1e823;584a81be8fddee4a8ac1e822;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1fda1;584a81be8fddee4a8ac1fda0;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1fd9e;584a81be8fddee4a8ac1fd9d;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1e457;584a81be8fddee4a8ac1e456;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1e8b1;584a81be8fddee4a8ac1e8b0;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1f029;584a81be8fddee4a8ac1f027;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1e8b5;584a81be8fddee4a8ac1e8b4;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1e7be;584a81be8fddee4a8ac1e7bd;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1fdec;584a81be8fddee4a8ac1fdeb;584a81be8fddee4a8ac1cd93;sameAs; +584a81be8fddee4a8ac1ea42;584a81be8fddee4a8ac1ea40;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1f387;584a81be8fddee4a8ac1f386;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1ea48;584a81be8fddee4a8ac1ea47;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1ecda;584a81be8fddee4a8ac1ecd9;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1edf0;584a81be8fddee4a8ac1edee;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1ebbb;584a81be8fddee4a8ac1ebba;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1fbd0;584a81be8fddee4a8ac1fbcf;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1edfa;584a81be8fddee4a8ac1edf9;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1f38d;584a81be8fddee4a8ac1f38c;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1fc9a;584a81be8fddee4a8ac1fc99;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1ebbe;584a81be8fddee4a8ac1ebbd;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1e8c8;584a81be8fddee4a8ac1e8c7;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1e8ad;584a81be8fddee4a8ac1e8ac;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1ebb7;584a81be8fddee4a8ac1ebb5;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1f64d;584a81be8fddee4a8ac1f64c;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1e7c4;584a81be8fddee4a8ac1e7c3;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1ecee;584a81be8fddee4a8ac1eced;584a81be8fddee4a8ac1cd95;sameAs; +584a81be8fddee4a8ac1fc93;584a81be8fddee4a8ac1fc91;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1fc97;584a81be8fddee4a8ac1fc96;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1fbd8;584a81be8fddee4a8ac1fbd7;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1eb71;584a81be8fddee4a8ac1eb59;584a81be8fddee4a8ac1cdc0;sameAs; +584a81be8fddee4a8ac1f02e;584a81be8fddee4a8ac1f02d;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1ece8;584a81be8fddee4a8ac1ece6;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1eea8;584a81be8fddee4a8ac1eea6;584a81be8fddee4a8ac1cd96;sameAs; +584a81be8fddee4a8ac1f37f;584a81be8fddee4a8ac1f37e;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1ee9b;584a81be8fddee4a8ac1ee99;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1fde6;584a81be8fddee4a8ac1fde5;584a81be8fddee4a8ac1cdbb;sameAs; +584a81be8fddee4a8ac1e7c1;584a81be8fddee4a8ac1e7c0;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1e81a;584a81be8fddee4a8ac1e818;584a81be8fddee4a8ac1cdbe;sameAs; +584a81be8fddee4a8ac1ce88;584a81be8fddee4a8ac1ce87;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1ce8d;584a81be8fddee4a8ac1ce8c;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1ce92;584a81be8fddee4a8ac1ce91;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1ce97;584a81be8fddee4a8ac1ce96;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cead;584a81be8fddee4a8ac1ceac;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cec3;584a81be8fddee4a8ac1cec2;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cec8;584a81be8fddee4a8ac1cec7;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cede;584a81be8fddee4a8ac1cedd;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cef4;584a81be8fddee4a8ac1cef3;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cf0a;584a81be8fddee4a8ac1cf09;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cf20;584a81be8fddee4a8ac1cf1f;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cf36;584a81be8fddee4a8ac1cf35;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cf3b;584a81be8fddee4a8ac1cf3a;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cf51;584a81be8fddee4a8ac1cf50;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cf67;584a81be8fddee4a8ac1cf66;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cf7d;584a81be8fddee4a8ac1cf7c;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cf82;584a81be8fddee4a8ac1cf81;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cf98;584a81be8fddee4a8ac1cf97;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cfae;584a81be8fddee4a8ac1cfad;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1cfb3;584a81be8fddee4a8ac1cfb2;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1cfc9;584a81be8fddee4a8ac1cfc8;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cfdf;584a81be8fddee4a8ac1cfde;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1cff5;584a81be8fddee4a8ac1cff4;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d00b;584a81be8fddee4a8ac1d00a;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d021;584a81be8fddee4a8ac1d020;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d026;584a81be8fddee4a8ac1d025;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d03c;584a81be8fddee4a8ac1d03b;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d052;584a81be8fddee4a8ac1d051;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d057;584a81be8fddee4a8ac1d056;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d06d;584a81be8fddee4a8ac1d06c;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d083;584a81be8fddee4a8ac1d082;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d099;584a81be8fddee4a8ac1d098;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d0af;584a81be8fddee4a8ac1d0ae;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d0b4;584a81be8fddee4a8ac1d0b3;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d0ca;584a81be8fddee4a8ac1d0c9;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d0cf;584a81be8fddee4a8ac1d0ce;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d0e5;584a81be8fddee4a8ac1d0e4;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d0fb;584a81be8fddee4a8ac1d0fa;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d111;584a81be8fddee4a8ac1d110;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d116;584a81be8fddee4a8ac1d115;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d11b;584a81be8fddee4a8ac1d11a;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d131;584a81be8fddee4a8ac1d130;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d147;584a81be8fddee4a8ac1d146;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d14c;584a81be8fddee4a8ac1d14b;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d151;584a81be8fddee4a8ac1d150;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d156;584a81be8fddee4a8ac1d155;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d15b;584a81be8fddee4a8ac1d15a;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d171;584a81be8fddee4a8ac1d170;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d187;584a81be8fddee4a8ac1d186;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d19d;584a81be8fddee4a8ac1d19c;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d1a2;584a81be8fddee4a8ac1d1a1;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d1b8;584a81be8fddee4a8ac1d1b7;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d1ce;584a81be8fddee4a8ac1d1cd;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d1e4;584a81be8fddee4a8ac1d1e3;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d1fa;584a81be8fddee4a8ac1d1f9;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d210;584a81be8fddee4a8ac1d20f;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d226;584a81be8fddee4a8ac1d225;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d23c;584a81be8fddee4a8ac1d23b;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d252;584a81be8fddee4a8ac1d251;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d268;584a81be8fddee4a8ac1d267;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d26d;584a81be8fddee4a8ac1d26c;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d272;584a81be8fddee4a8ac1d271;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d288;584a81be8fddee4a8ac1d287;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d29e;584a81be8fddee4a8ac1d29d;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d2b4;584a81be8fddee4a8ac1d2b3;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d2ca;584a81be8fddee4a8ac1d2c9;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d2e0;584a81be8fddee4a8ac1d2df;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d2f6;584a81be8fddee4a8ac1d2f5;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d2fb;584a81be8fddee4a8ac1d2fa;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d300;584a81be8fddee4a8ac1d2ff;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d316;584a81be8fddee4a8ac1d315;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d31b;584a81be8fddee4a8ac1d31a;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d331;584a81be8fddee4a8ac1d330;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d347;584a81be8fddee4a8ac1d346;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d34c;584a81be8fddee4a8ac1d34b;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d362;584a81be8fddee4a8ac1d361;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d367;584a81be8fddee4a8ac1d366;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d36c;584a81be8fddee4a8ac1d36b;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d382;584a81be8fddee4a8ac1d381;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d387;584a81be8fddee4a8ac1d386;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d38c;584a81be8fddee4a8ac1d38b;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d391;584a81be8fddee4a8ac1d390;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d3a7;584a81be8fddee4a8ac1d3a6;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d3ac;584a81be8fddee4a8ac1d3ab;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d3c2;584a81be8fddee4a8ac1d3c1;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d3d8;584a81be8fddee4a8ac1d3d7;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d3ee;584a81be8fddee4a8ac1d3ed;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d404;584a81be8fddee4a8ac1d403;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d41a;584a81be8fddee4a8ac1d419;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d430;584a81be8fddee4a8ac1d42f;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d446;584a81be8fddee4a8ac1d445;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d45c;584a81be8fddee4a8ac1d45b;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d472;584a81be8fddee4a8ac1d471;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d477;584a81be8fddee4a8ac1d476;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d47c;584a81be8fddee4a8ac1d47b;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d492;584a81be8fddee4a8ac1d491;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4a8;584a81be8fddee4a8ac1d4a7;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4ad;584a81be8fddee4a8ac1d4ac;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4b2;584a81be8fddee4a8ac1d4b1;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4b7;584a81be8fddee4a8ac1d4b6;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d4cd;584a81be8fddee4a8ac1d4cc;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4d2;584a81be8fddee4a8ac1d4d1;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4d7;584a81be8fddee4a8ac1d4d6;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d4dc;584a81be8fddee4a8ac1d4db;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d4e1;584a81be8fddee4a8ac1d4e0;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d4f7;584a81be8fddee4a8ac1d4f6;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d50d;584a81be8fddee4a8ac1d50c;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d523;584a81be8fddee4a8ac1d522;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d539;584a81be8fddee4a8ac1d538;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d54f;584a81be8fddee4a8ac1d54e;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d565;584a81be8fddee4a8ac1d564;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d56a;584a81be8fddee4a8ac1d569;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d580;584a81be8fddee4a8ac1d57f;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d596;584a81be8fddee4a8ac1d595;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d5ac;584a81be8fddee4a8ac1d5ab;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d5b1;584a81be8fddee4a8ac1d5b0;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d5b6;584a81be8fddee4a8ac1d5b5;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d5bb;584a81be8fddee4a8ac1d5ba;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d5d1;584a81be8fddee4a8ac1d5d0;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d5d6;584a81be8fddee4a8ac1d5d5;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d5ec;584a81be8fddee4a8ac1d5eb;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d602;584a81be8fddee4a8ac1d601;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d618;584a81be8fddee4a8ac1d617;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d62e;584a81be8fddee4a8ac1d62d;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d644;584a81be8fddee4a8ac1d643;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d65a;584a81be8fddee4a8ac1d659;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d670;584a81be8fddee4a8ac1d66f;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d686;584a81be8fddee4a8ac1d685;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d69c;584a81be8fddee4a8ac1d69b;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d6a1;584a81be8fddee4a8ac1d6a0;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d6b7;584a81be8fddee4a8ac1d6b6;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d6bc;584a81be8fddee4a8ac1d6bb;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d6c1;584a81be8fddee4a8ac1d6c0;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d6d7;584a81be8fddee4a8ac1d6d6;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d6ed;584a81be8fddee4a8ac1d6ec;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d703;584a81be8fddee4a8ac1d702;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d708;584a81be8fddee4a8ac1d707;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d71e;584a81be8fddee4a8ac1d71d;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d734;584a81be8fddee4a8ac1d733;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d74a;584a81be8fddee4a8ac1d749;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d74f;584a81be8fddee4a8ac1d74e;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d765;584a81be8fddee4a8ac1d764;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d77b;584a81be8fddee4a8ac1d77a;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d791;584a81be8fddee4a8ac1d790;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d7a7;584a81be8fddee4a8ac1d7a6;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d7bd;584a81be8fddee4a8ac1d7bc;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d7d3;584a81be8fddee4a8ac1d7d2;584a81be8fddee4a8ac1cdbe;sentBy; +584a81be8fddee4a8ac1d7e9;584a81be8fddee4a8ac1d7e8;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d7ee;584a81be8fddee4a8ac1d7ed;584a81be8fddee4a8ac1cdc0;sentBy; +584a81be8fddee4a8ac1d804;584a81be8fddee4a8ac1d803;584a81be8fddee4a8ac1cdbb;sentBy; +584a81be8fddee4a8ac1d805;584a81be8fddee4a8ac1d803;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d7ef;584a81be8fddee4a8ac1d7ed;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d7ea;584a81be8fddee4a8ac1d7e8;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d7d4;584a81be8fddee4a8ac1d7d2;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d7be;584a81be8fddee4a8ac1d7bc;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d7a8;584a81be8fddee4a8ac1d7a6;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d792;584a81be8fddee4a8ac1d790;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d77c;584a81be8fddee4a8ac1d77a;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d766;584a81be8fddee4a8ac1d764;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d750;584a81be8fddee4a8ac1d74e;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d74b;584a81be8fddee4a8ac1d749;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d735;584a81be8fddee4a8ac1d733;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d71f;584a81be8fddee4a8ac1d71d;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d709;584a81be8fddee4a8ac1d707;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d704;584a81be8fddee4a8ac1d702;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d6ee;584a81be8fddee4a8ac1d6ec;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d6d8;584a81be8fddee4a8ac1d6d6;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d6c2;584a81be8fddee4a8ac1d6c0;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d6bd;584a81be8fddee4a8ac1d6bb;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d6b8;584a81be8fddee4a8ac1d6b6;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d6a2;584a81be8fddee4a8ac1d6a0;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d69d;584a81be8fddee4a8ac1d69b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d687;584a81be8fddee4a8ac1d685;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d671;584a81be8fddee4a8ac1d66f;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d65b;584a81be8fddee4a8ac1d659;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d645;584a81be8fddee4a8ac1d643;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d62f;584a81be8fddee4a8ac1d62d;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d619;584a81be8fddee4a8ac1d617;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d603;584a81be8fddee4a8ac1d601;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d5ed;584a81be8fddee4a8ac1d5eb;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d5d7;584a81be8fddee4a8ac1d5d5;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d5d2;584a81be8fddee4a8ac1d5d0;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d5bc;584a81be8fddee4a8ac1d5ba;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d5b7;584a81be8fddee4a8ac1d5b5;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d5b2;584a81be8fddee4a8ac1d5b0;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d5ad;584a81be8fddee4a8ac1d5ab;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d597;584a81be8fddee4a8ac1d595;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d581;584a81be8fddee4a8ac1d57f;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d56b;584a81be8fddee4a8ac1d569;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d566;584a81be8fddee4a8ac1d564;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d550;584a81be8fddee4a8ac1d54e;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d53a;584a81be8fddee4a8ac1d538;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d524;584a81be8fddee4a8ac1d522;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d50e;584a81be8fddee4a8ac1d50c;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d4f8;584a81be8fddee4a8ac1d4f6;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d4e2;584a81be8fddee4a8ac1d4e0;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d4dd;584a81be8fddee4a8ac1d4db;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d4d8;584a81be8fddee4a8ac1d4d6;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d4d3;584a81be8fddee4a8ac1d4d1;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d4ce;584a81be8fddee4a8ac1d4cc;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d4b8;584a81be8fddee4a8ac1d4b6;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d4b3;584a81be8fddee4a8ac1d4b1;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d4ae;584a81be8fddee4a8ac1d4ac;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d4a9;584a81be8fddee4a8ac1d4a7;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d493;584a81be8fddee4a8ac1d491;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d47d;584a81be8fddee4a8ac1d47b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d478;584a81be8fddee4a8ac1d476;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d473;584a81be8fddee4a8ac1d471;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d45d;584a81be8fddee4a8ac1d45b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d447;584a81be8fddee4a8ac1d445;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d431;584a81be8fddee4a8ac1d42f;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d41b;584a81be8fddee4a8ac1d419;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d405;584a81be8fddee4a8ac1d403;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d3ef;584a81be8fddee4a8ac1d3ed;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d3d9;584a81be8fddee4a8ac1d3d7;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d3c3;584a81be8fddee4a8ac1d3c1;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d3ad;584a81be8fddee4a8ac1d3ab;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d3a8;584a81be8fddee4a8ac1d3a6;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d392;584a81be8fddee4a8ac1d390;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d38d;584a81be8fddee4a8ac1d38b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d388;584a81be8fddee4a8ac1d386;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d383;584a81be8fddee4a8ac1d381;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d36d;584a81be8fddee4a8ac1d36b;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d368;584a81be8fddee4a8ac1d366;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d363;584a81be8fddee4a8ac1d361;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d34d;584a81be8fddee4a8ac1d34b;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d348;584a81be8fddee4a8ac1d346;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d332;584a81be8fddee4a8ac1d330;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d31c;584a81be8fddee4a8ac1d31a;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d317;584a81be8fddee4a8ac1d315;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d301;584a81be8fddee4a8ac1d2ff;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d2fc;584a81be8fddee4a8ac1d2fa;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d2f7;584a81be8fddee4a8ac1d2f5;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d2e1;584a81be8fddee4a8ac1d2df;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d2cb;584a81be8fddee4a8ac1d2c9;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d2b5;584a81be8fddee4a8ac1d2b3;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d29f;584a81be8fddee4a8ac1d29d;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d289;584a81be8fddee4a8ac1d287;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d273;584a81be8fddee4a8ac1d271;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d26e;584a81be8fddee4a8ac1d26c;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d269;584a81be8fddee4a8ac1d267;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d253;584a81be8fddee4a8ac1d251;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d23d;584a81be8fddee4a8ac1d23b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d227;584a81be8fddee4a8ac1d225;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d211;584a81be8fddee4a8ac1d20f;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d1fb;584a81be8fddee4a8ac1d1f9;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d1e5;584a81be8fddee4a8ac1d1e3;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d1cf;584a81be8fddee4a8ac1d1cd;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d1b9;584a81be8fddee4a8ac1d1b7;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d1a3;584a81be8fddee4a8ac1d1a1;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d19e;584a81be8fddee4a8ac1d19c;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d188;584a81be8fddee4a8ac1d186;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d172;584a81be8fddee4a8ac1d170;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d15c;584a81be8fddee4a8ac1d15a;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d157;584a81be8fddee4a8ac1d155;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d152;584a81be8fddee4a8ac1d150;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d14d;584a81be8fddee4a8ac1d14b;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d148;584a81be8fddee4a8ac1d146;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d132;584a81be8fddee4a8ac1d130;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d11c;584a81be8fddee4a8ac1d11a;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d117;584a81be8fddee4a8ac1d115;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d112;584a81be8fddee4a8ac1d110;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d0fc;584a81be8fddee4a8ac1d0fa;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d0e6;584a81be8fddee4a8ac1d0e4;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d0d0;584a81be8fddee4a8ac1d0ce;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d0cb;584a81be8fddee4a8ac1d0c9;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d0b5;584a81be8fddee4a8ac1d0b3;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d0b0;584a81be8fddee4a8ac1d0ae;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d09a;584a81be8fddee4a8ac1d098;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d084;584a81be8fddee4a8ac1d082;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d06e;584a81be8fddee4a8ac1d06c;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d058;584a81be8fddee4a8ac1d056;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d053;584a81be8fddee4a8ac1d051;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d03d;584a81be8fddee4a8ac1d03b;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1d027;584a81be8fddee4a8ac1d025;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d022;584a81be8fddee4a8ac1d020;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1d00c;584a81be8fddee4a8ac1d00a;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cff6;584a81be8fddee4a8ac1cff4;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cfe0;584a81be8fddee4a8ac1cfde;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1cfca;584a81be8fddee4a8ac1cfc8;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cfb4;584a81be8fddee4a8ac1cfb2;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1cfaf;584a81be8fddee4a8ac1cfad;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cf99;584a81be8fddee4a8ac1cf97;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cf83;584a81be8fddee4a8ac1cf81;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1cf7e;584a81be8fddee4a8ac1cf7c;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1cf68;584a81be8fddee4a8ac1cf66;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1cf52;584a81be8fddee4a8ac1cf50;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cf3c;584a81be8fddee4a8ac1cf3a;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1cf37;584a81be8fddee4a8ac1cf35;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1cf21;584a81be8fddee4a8ac1cf1f;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1cf0b;584a81be8fddee4a8ac1cf09;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cef5;584a81be8fddee4a8ac1cef3;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1cedf;584a81be8fddee4a8ac1cedd;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1cec9;584a81be8fddee4a8ac1cec7;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1cec4;584a81be8fddee4a8ac1cec2;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1ceae;584a81be8fddee4a8ac1ceac;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1ce98;584a81be8fddee4a8ac1ce96;584a81be8fddee4a8ac1cd95;sentTo; +584a81be8fddee4a8ac1ce93;584a81be8fddee4a8ac1ce91;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1ce8e;584a81be8fddee4a8ac1ce8c;584a81be8fddee4a8ac1cd93;sentTo; +584a81be8fddee4a8ac1ce89;584a81be8fddee4a8ac1ce87;584a81be8fddee4a8ac1cd96;sentTo; +584a81be8fddee4a8ac1d5f5;584a81be8fddee4a8ac1d5f4;584a81be8fddee4a8ac1d5ef;serves; +584a81be8fddee4a8ac1d324;584a81be8fddee4a8ac1d323;584a81be8fddee4a8ac1d31e;serves; +584a81be8fddee4a8ac1d13a;584a81be8fddee4a8ac1d139;584a81be8fddee4a8ac1d134;serves; +584a81be8fddee4a8ac1d5df;584a81be8fddee4a8ac1d5de;584a81be8fddee4a8ac1d5d9;serves; +584a81be8fddee4a8ac1cefd;584a81be8fddee4a8ac1cefc;584a81be8fddee4a8ac1cef7;serves; +584a81be8fddee4a8ac1d309;584a81be8fddee4a8ac1d308;584a81be8fddee4a8ac1d303;serves; +584a81be8fddee4a8ac1d5c4;584a81be8fddee4a8ac1d5c3;584a81be8fddee4a8ac1d5be;serves; +584a81be8fddee4a8ac1d124;584a81be8fddee4a8ac1d123;584a81be8fddee4a8ac1d11e;serves; +584a81be8fddee4a8ac1cf5a;584a81be8fddee4a8ac1cf59;584a81be8fddee4a8ac1cf54;serves; +584a81be8fddee4a8ac1cffe;584a81be8fddee4a8ac1cffd;584a81be8fddee4a8ac1cff8;serves; +584a81be8fddee4a8ac1d2e9;584a81be8fddee4a8ac1d2e8;584a81be8fddee4a8ac1d2e3;serves; +584a81be8fddee4a8ac1d59f;584a81be8fddee4a8ac1d59e;584a81be8fddee4a8ac1d599;serves; +584a81be8fddee4a8ac1d2d3;584a81be8fddee4a8ac1d2d2;584a81be8fddee4a8ac1d2cd;serves; +584a81be8fddee4a8ac1d589;584a81be8fddee4a8ac1d588;584a81be8fddee4a8ac1d583;serves; +584a81be8fddee4a8ac1d573;584a81be8fddee4a8ac1d572;584a81be8fddee4a8ac1d56d;serves; +584a81be8fddee4a8ac1cfe8;584a81be8fddee4a8ac1cfe7;584a81be8fddee4a8ac1cfe2;serves; +584a81be8fddee4a8ac1d104;584a81be8fddee4a8ac1d103;584a81be8fddee4a8ac1d0fe;serves; +584a81be8fddee4a8ac1d558;584a81be8fddee4a8ac1d557;584a81be8fddee4a8ac1d552;serves; +584a81be8fddee4a8ac1d2bd;584a81be8fddee4a8ac1d2bc;584a81be8fddee4a8ac1d2b7;serves; +584a81be8fddee4a8ac1d2a7;584a81be8fddee4a8ac1d2a6;584a81be8fddee4a8ac1d2a1;serves; +584a81be8fddee4a8ac1d542;584a81be8fddee4a8ac1d541;584a81be8fddee4a8ac1d53c;serves; +584a81be8fddee4a8ac1d52c;584a81be8fddee4a8ac1d52b;584a81be8fddee4a8ac1d526;serves; +584a81be8fddee4a8ac1cee7;584a81be8fddee4a8ac1cee6;584a81be8fddee4a8ac1cee1;serves; +584a81be8fddee4a8ac1d516;584a81be8fddee4a8ac1d515;584a81be8fddee4a8ac1d510;serves; +584a81be8fddee4a8ac1d291;584a81be8fddee4a8ac1d290;584a81be8fddee4a8ac1d28b;serves; +584a81be8fddee4a8ac1d0ee;584a81be8fddee4a8ac1d0ed;584a81be8fddee4a8ac1d0e8;serves; +584a81be8fddee4a8ac1d500;584a81be8fddee4a8ac1d4ff;584a81be8fddee4a8ac1d4fa;serves; +584a81be8fddee4a8ac1d27b;584a81be8fddee4a8ac1d27a;584a81be8fddee4a8ac1d275;serves; +584a81be8fddee4a8ac1d4ea;584a81be8fddee4a8ac1d4e9;584a81be8fddee4a8ac1d4e4;serves; +584a81be8fddee4a8ac1d0d8;584a81be8fddee4a8ac1d0d7;584a81be8fddee4a8ac1d0d2;serves; +584a81be8fddee4a8ac1cfd2;584a81be8fddee4a8ac1cfd1;584a81be8fddee4a8ac1cfcc;serves; +584a81be8fddee4a8ac1cf44;584a81be8fddee4a8ac1cf43;584a81be8fddee4a8ac1cf3e;serves; +584a81be8fddee4a8ac1d25b;584a81be8fddee4a8ac1d25a;584a81be8fddee4a8ac1d255;serves; +584a81be8fddee4a8ac1cfbc;584a81be8fddee4a8ac1cfbb;584a81be8fddee4a8ac1cfb6;serves; +584a81be8fddee4a8ac1d4c0;584a81be8fddee4a8ac1d4bf;584a81be8fddee4a8ac1d4ba;serves; +584a81be8fddee4a8ac1d0bd;584a81be8fddee4a8ac1d0bc;584a81be8fddee4a8ac1d0b7;serves; +584a81be8fddee4a8ac1d245;584a81be8fddee4a8ac1d244;584a81be8fddee4a8ac1d23f;serves; +584a81be8fddee4a8ac1d22f;584a81be8fddee4a8ac1d22e;584a81be8fddee4a8ac1d229;serves; +584a81be8fddee4a8ac1d49b;584a81be8fddee4a8ac1d49a;584a81be8fddee4a8ac1d495;serves; +584a81be8fddee4a8ac1ceb6;584a81be8fddee4a8ac1ceb5;584a81be8fddee4a8ac1ceb0;serves; +584a81be8fddee4a8ac1ced1;584a81be8fddee4a8ac1ced0;584a81be8fddee4a8ac1cecb;serves; +584a81be8fddee4a8ac1d485;584a81be8fddee4a8ac1d484;584a81be8fddee4a8ac1d47f;serves; +584a81be8fddee4a8ac1d219;584a81be8fddee4a8ac1d218;584a81be8fddee4a8ac1d213;serves; +584a81be8fddee4a8ac1d0a2;584a81be8fddee4a8ac1d0a1;584a81be8fddee4a8ac1d09c;serves; +584a81be8fddee4a8ac1d203;584a81be8fddee4a8ac1d202;584a81be8fddee4a8ac1d1fd;serves; +584a81be8fddee4a8ac1d465;584a81be8fddee4a8ac1d464;584a81be8fddee4a8ac1d45f;serves; +584a81be8fddee4a8ac1d44f;584a81be8fddee4a8ac1d44e;584a81be8fddee4a8ac1d449;serves; +584a81be8fddee4a8ac1d08c;584a81be8fddee4a8ac1d08b;584a81be8fddee4a8ac1d086;serves; +584a81be8fddee4a8ac1d1ed;584a81be8fddee4a8ac1d1ec;584a81be8fddee4a8ac1d1e7;serves; +584a81be8fddee4a8ac1d7f7;584a81be8fddee4a8ac1d7f6;584a81be8fddee4a8ac1d7f1;serves; +584a81be8fddee4a8ac1d439;584a81be8fddee4a8ac1d438;584a81be8fddee4a8ac1d433;serves; +584a81be8fddee4a8ac1d1d7;584a81be8fddee4a8ac1d1d6;584a81be8fddee4a8ac1d1d1;serves; +584a81be8fddee4a8ac1d7dc;584a81be8fddee4a8ac1d7db;584a81be8fddee4a8ac1d7d6;serves; +584a81be8fddee4a8ac1d423;584a81be8fddee4a8ac1d422;584a81be8fddee4a8ac1d41d;serves; +584a81be8fddee4a8ac1cf29;584a81be8fddee4a8ac1cf28;584a81be8fddee4a8ac1cf23;serves; +584a81be8fddee4a8ac1d7c6;584a81be8fddee4a8ac1d7c5;584a81be8fddee4a8ac1d7c0;serves; +584a81be8fddee4a8ac1d7b0;584a81be8fddee4a8ac1d7af;584a81be8fddee4a8ac1d7aa;serves; +584a81be8fddee4a8ac1d3f7;584a81be8fddee4a8ac1d3f6;584a81be8fddee4a8ac1d3f1;serves; +584a81be8fddee4a8ac1d076;584a81be8fddee4a8ac1d075;584a81be8fddee4a8ac1d070;serves; +584a81be8fddee4a8ac1d79a;584a81be8fddee4a8ac1d799;584a81be8fddee4a8ac1d794;serves; +584a81be8fddee4a8ac1d1c1;584a81be8fddee4a8ac1d1c0;584a81be8fddee4a8ac1d1bb;serves; +584a81be8fddee4a8ac1d784;584a81be8fddee4a8ac1d783;584a81be8fddee4a8ac1d77e;serves; +584a81be8fddee4a8ac1d3e1;584a81be8fddee4a8ac1d3e0;584a81be8fddee4a8ac1d3db;serves; +584a81be8fddee4a8ac1d76e;584a81be8fddee4a8ac1d76d;584a81be8fddee4a8ac1d768;serves; +584a81be8fddee4a8ac1d758;584a81be8fddee4a8ac1d757;584a81be8fddee4a8ac1d752;serves; +584a81be8fddee4a8ac1d3cb;584a81be8fddee4a8ac1d3ca;584a81be8fddee4a8ac1d3c5;serves; +584a81be8fddee4a8ac1d1ab;584a81be8fddee4a8ac1d1aa;584a81be8fddee4a8ac1d1a5;serves; +584a81be8fddee4a8ac1d3b5;584a81be8fddee4a8ac1d3b4;584a81be8fddee4a8ac1d3af;serves; +584a81be8fddee4a8ac1d73d;584a81be8fddee4a8ac1d73c;584a81be8fddee4a8ac1d737;serves; +584a81be8fddee4a8ac1d727;584a81be8fddee4a8ac1d726;584a81be8fddee4a8ac1d721;serves; +584a81be8fddee4a8ac1cfa1;584a81be8fddee4a8ac1cfa0;584a81be8fddee4a8ac1cf9b;serves; +584a81be8fddee4a8ac1d711;584a81be8fddee4a8ac1d710;584a81be8fddee4a8ac1d70b;serves; +584a81be8fddee4a8ac1cf8b;584a81be8fddee4a8ac1cf8a;584a81be8fddee4a8ac1cf85;serves; +584a81be8fddee4a8ac1d190;584a81be8fddee4a8ac1d18f;584a81be8fddee4a8ac1d18a;serves; +584a81be8fddee4a8ac1d6f6;584a81be8fddee4a8ac1d6f5;584a81be8fddee4a8ac1d6f0;serves; +584a81be8fddee4a8ac1d39a;584a81be8fddee4a8ac1d399;584a81be8fddee4a8ac1d394;serves; +584a81be8fddee4a8ac1d060;584a81be8fddee4a8ac1d05f;584a81be8fddee4a8ac1d05a;serves; +584a81be8fddee4a8ac1d6e0;584a81be8fddee4a8ac1d6df;584a81be8fddee4a8ac1d6da;serves; +584a81be8fddee4a8ac1cf13;584a81be8fddee4a8ac1cf12;584a81be8fddee4a8ac1cf0d;serves; +584a81be8fddee4a8ac1d6ca;584a81be8fddee4a8ac1d6c9;584a81be8fddee4a8ac1d6c4;serves; +584a81be8fddee4a8ac1d17a;584a81be8fddee4a8ac1d179;584a81be8fddee4a8ac1d174;serves; +584a81be8fddee4a8ac1d375;584a81be8fddee4a8ac1d374;584a81be8fddee4a8ac1d36f;serves; +584a81be8fddee4a8ac1cea0;584a81be8fddee4a8ac1ce9f;584a81be8fddee4a8ac1ce9a;serves; +584a81be8fddee4a8ac1d6aa;584a81be8fddee4a8ac1d6a9;584a81be8fddee4a8ac1d6a4;serves; +584a81be8fddee4a8ac1d164;584a81be8fddee4a8ac1d163;584a81be8fddee4a8ac1d15e;serves; +584a81be8fddee4a8ac1d68f;584a81be8fddee4a8ac1d68e;584a81be8fddee4a8ac1d689;serves; +584a81be8fddee4a8ac1d045;584a81be8fddee4a8ac1d044;584a81be8fddee4a8ac1d03f;serves; +584a81be8fddee4a8ac1d355;584a81be8fddee4a8ac1d354;584a81be8fddee4a8ac1d34f;serves; +584a81be8fddee4a8ac1d679;584a81be8fddee4a8ac1d678;584a81be8fddee4a8ac1d673;serves; +584a81be8fddee4a8ac1d02f;584a81be8fddee4a8ac1d02e;584a81be8fddee4a8ac1d029;serves; +584a81be8fddee4a8ac1d663;584a81be8fddee4a8ac1d662;584a81be8fddee4a8ac1d65d;serves; +584a81be8fddee4a8ac1cf70;584a81be8fddee4a8ac1cf6f;584a81be8fddee4a8ac1cf6a;serves; +584a81be8fddee4a8ac1d64d;584a81be8fddee4a8ac1d64c;584a81be8fddee4a8ac1d647;serves; +584a81be8fddee4a8ac1d637;584a81be8fddee4a8ac1d636;584a81be8fddee4a8ac1d631;serves; +584a81be8fddee4a8ac1d40d;584a81be8fddee4a8ac1d40c;584a81be8fddee4a8ac1d407;serves; +584a81be8fddee4a8ac1d33a;584a81be8fddee4a8ac1d339;584a81be8fddee4a8ac1d334;serves; +584a81be8fddee4a8ac1d621;584a81be8fddee4a8ac1d620;584a81be8fddee4a8ac1d61b;serves; +584a81be8fddee4a8ac1d60b;584a81be8fddee4a8ac1d60a;584a81be8fddee4a8ac1d605;serves; +584a81be8fddee4a8ac1d014;584a81be8fddee4a8ac1d013;584a81be8fddee4a8ac1d00e;serves; diff --git a/gradoop-examples/src/main/resources/data/csv/foodbroker/metadata.csv b/gradoop-examples/src/main/resources/data/csv/foodbroker/metadata.csv new file mode 100644 index 000000000000..f0ef9057dc18 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/foodbroker/metadata.csv @@ -0,0 +1,32 @@ +v;Client;account:string,city:string,contactPhone:string,erpCustNum:string,name:string,num:string,quality:double,superType:string +v;Customer;city:string,name:string,num:string,quality:double,superType:string +v;DeliveryNote;date:long,num:string,superType:string,trackingCode:string +v;Employee;city:string,gender:string,name:string,num:string,quality:double,superType:string +v;Logistics;city:string,name:string,num:string,quality:double,superType:string +v;Product;category:string,name:string,num:string,price:double,price:int,quality:double,superType:string +v;PurchInvoice;date:long,expense:double,expense:int,num:string,superType:string,text:string +v;PurchOrder;date:long,num:string,superType:string +v;SalesInvoice;date:long,num:string,revenue:double,revenue:int,superType:string,text:string +v;SalesOrder;date:long,deliveryDate:long,num:string,superType:string +v;SalesQuotation;date:long,num:string,superType:string +v;Ticket;createdAt:long,erpSoNum:string,problem:string,superType:string +v;User;city:string,email:string,erpEmplNum:string,gender:string,name:string,num:string,quality:double,superType:string +v;Vendor;city:string,name:string,num:string,quality:double,superType:string +e;PurchOrderLine;purchPrice:double,quantity:int,salesOrderLine:string,superType:string +e;SalesOrderLine;purchOrderLine:string,quantity:int,salesPrice:double,superType:string +e;SalesQuotationLine;purchPrice:double,purchPrice:int,quantity:int,salesPrice:double,superType:string +e;allocatedTo; +e;basedOn; +e;concerns; +e;contains; +e;createdBy; +e;createdFor; +e;openedBy; +e;operatedBy; +e;placedAt; +e;processedBy; +e;receivedFrom; +e;sameAs; +e;sentBy; +e;sentTo; +e;serves; diff --git a/gradoop-examples/src/main/resources/data/csv/foodbroker/vertices.csv b/gradoop-examples/src/main/resources/data/csv/foodbroker/vertices.csv new file mode 100644 index 000000000000..1e4a1003b777 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/foodbroker/vertices.csv @@ -0,0 +1,804 @@ +584a81be8fddee4a8ac1fdeb;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1e8b4;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1e822;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1eced;Client;CL584a81be8fddee4a8ac1cd95|Winston–Salem|0123456789|584a81be8fddee4a8ac1cd95|savory stand|CIT_CLI00000002|0.66|M +584a81be8fddee4a8ac1f38c;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1f033;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1f64c;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1e7c3;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1ebbd;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1e456;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1fda0;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1eb74;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1fbd7;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1eea6;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1fc99;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1ea47;Client;CL584a81be8fddee4a8ac1cd96|Atlanta|0123456789|584a81be8fddee4a8ac1cd96|cheap corner|CIT_CLI00000003|0.33|M +584a81be8fddee4a8ac1ee01;Client;CL584a81be8fddee4a8ac1cd93|Vancouver|0123456789|584a81be8fddee4a8ac1cd93|spicy corner|CIT_CLI00000001|0.01|M +584a81be8fddee4a8ac1cd96;Customer;Atlanta|cheap corner|ERP_CUS00000003|0.33|M +584a81be8fddee4a8ac1cd95;Customer;Winston–Salem|savory stand|ERP_CUS00000002|0.66|M +584a81be8fddee4a8ac1cd93;Customer;Vancouver|spicy corner|ERP_CUS00000001|0.01|M +584a81be8fddee4a8ac1d625;DeliveryNote;1388790000000|DLV000123-000516|T|***TODO*** +584a81be8fddee4a8ac1d772;DeliveryNote;1389567600000|DLV000142-000605|T|***TODO*** +584a81be8fddee4a8ac1d128;DeliveryNote;1389222000000|DLV000041-000179|T|***TODO*** +584a81be8fddee4a8ac1d2ed;DeliveryNote;1389222000000|DLV000067-000300|T|***TODO*** +584a81be8fddee4a8ac1d60f;DeliveryNote;1389135600000|DLV000122-000510|T|***TODO*** +584a81be8fddee4a8ac1d2d7;DeliveryNote;1389222000000|DLV000066-000294|T|***TODO*** +584a81be8fddee4a8ac1d2c1;DeliveryNote;1390345200000|DLV000065-000288|T|***TODO*** +584a81be8fddee4a8ac1d2ab;DeliveryNote;1390431600000|DLV000064-000282|T|***TODO*** +584a81be8fddee4a8ac1d295;DeliveryNote;1389394800000|DLV000063-000276|T|***TODO*** +584a81be8fddee4a8ac1d27f;DeliveryNote;1389135600000|DLV000062-000270|T|***TODO*** +584a81be8fddee4a8ac1d5f9;DeliveryNote;1388962800000|DLV000121-000504|T|***TODO*** +584a81be8fddee4a8ac1cf74;DeliveryNote;1389135600000|DLV000015-000063|T|***TODO*** +584a81be8fddee4a8ac1d13e;DeliveryNote;1388617200000|DLV000042-000185|T|***TODO*** +584a81be8fddee4a8ac1d25f;DeliveryNote;1389654000000|DLV000059-000262|T|***TODO*** +584a81be8fddee4a8ac1cf2d;DeliveryNote;1389999600000|DLV000011-000044|T|***TODO*** +584a81be8fddee4a8ac1d788;DeliveryNote;1389049200000|DLV000143-000611|T|***TODO*** +584a81be8fddee4a8ac1d5e3;DeliveryNote;1388617200000|DLV000120-000498|T|***TODO*** +584a81be8fddee4a8ac1cf5e;DeliveryNote;1389913200000|DLV000014-000057|T|***TODO*** +584a81be8fddee4a8ac1d168;DeliveryNote;1388790000000|DLV000047-000195|T|***TODO*** +584a81be8fddee4a8ac1d249;DeliveryNote;1389308400000|DLV000058-000256|T|***TODO*** +584a81be8fddee4a8ac1d049;DeliveryNote;1388790000000|DLV000027-000120|T|***TODO*** +584a81be8fddee4a8ac1d233;DeliveryNote;1390258800000|DLV000057-000250|T|***TODO*** +584a81be8fddee4a8ac1d21d;DeliveryNote;1388790000000|DLV000056-000244|T|***TODO*** +584a81be8fddee4a8ac1d207;DeliveryNote;1390345200000|DLV000055-000238|T|***TODO*** +584a81be8fddee4a8ac1d1f1;DeliveryNote;1389222000000|DLV000054-000232|T|***TODO*** +584a81be8fddee4a8ac1d1db;DeliveryNote;1390518000000|DLV000053-000226|T|***TODO*** +584a81be8fddee4a8ac1d5c8;DeliveryNote;1388703600000|DLV000118-000491|T|***TODO*** +584a81be8fddee4a8ac1ceba;DeliveryNote;1389049200000|DLV000005-000013|T|***TODO*** +584a81be8fddee4a8ac1d17e;DeliveryNote;1389222000000|DLV000048-000201|T|***TODO*** +584a81be8fddee4a8ac1d194;DeliveryNote;1389654000000|DLV000049-000207|T|***TODO*** +584a81be8fddee4a8ac1d1c5;DeliveryNote;1390431600000|DLV000052-000220|T|***TODO*** +584a81be8fddee4a8ac1d7e0;DeliveryNote;1389394800000|DLV000147-000635|T|***TODO*** +584a81be8fddee4a8ac1cf48;DeliveryNote;1390518000000|DLV000013-000051|T|***TODO*** +584a81be8fddee4a8ac1d1af;DeliveryNote;1389049200000|DLV000051-000214|T|***TODO*** +584a81be8fddee4a8ac1d5a3;DeliveryNote;1389999600000|DLV000114-000482|T|***TODO*** +584a81be8fddee4a8ac1d58d;DeliveryNote;1389999600000|DLV000113-000476|T|***TODO*** +584a81be8fddee4a8ac1d715;DeliveryNote;1389222000000|DLV000137-000580|T|***TODO*** +584a81be8fddee4a8ac1d7fb;DeliveryNote;1388876400000|DLV000149-000642|T|***TODO*** +584a81be8fddee4a8ac1d577;DeliveryNote;1388703600000|DLV000112-000470|T|***TODO*** +584a81be8fddee4a8ac1d033;DeliveryNote;1389308400000|DLV000026-000114|T|***TODO*** +584a81be8fddee4a8ac1d090;DeliveryNote;1390172400000|DLV000031-000139|T|***TODO*** +584a81be8fddee4a8ac1cf01;DeliveryNote;1389308400000|DLV000009-000032|T|***TODO*** +584a81be8fddee4a8ac1d6fa;DeliveryNote;1389308400000|DLV000135-000573|T|***TODO*** +584a81be8fddee4a8ac1ceeb;DeliveryNote;1388790000000|DLV000008-000026|T|***TODO*** +584a81be8fddee4a8ac1d6e4;DeliveryNote;1389567600000|DLV000134-000567|T|***TODO*** +584a81be8fddee4a8ac1d55c;DeliveryNote;1388962800000|DLV000110-000463|T|***TODO*** +584a81be8fddee4a8ac1d6ce;DeliveryNote;1388790000000|DLV000133-000561|T|***TODO*** +584a81be8fddee4a8ac1d546;DeliveryNote;1389049200000|DLV000109-000457|T|***TODO*** +584a81be8fddee4a8ac1d07a;DeliveryNote;1389999600000|DLV000030-000133|T|***TODO*** +584a81be8fddee4a8ac1d530;DeliveryNote;1389826800000|DLV000108-000451|T|***TODO*** +584a81be8fddee4a8ac1d51a;DeliveryNote;1389826800000|DLV000107-000445|T|***TODO*** +584a81be8fddee4a8ac1d6ae;DeliveryNote;1390431600000|DLV000130-000553|T|***TODO*** +584a81be8fddee4a8ac1d75c;DeliveryNote;1388703600000|DLV000141-000599|T|***TODO*** +584a81be8fddee4a8ac1d504;DeliveryNote;1388962800000|DLV000106-000439|T|***TODO*** +584a81be8fddee4a8ac1d0a6;DeliveryNote;1390258800000|DLV000032-000145|T|***TODO*** +584a81be8fddee4a8ac1d4ee;DeliveryNote;1388876400000|DLV000105-000433|T|***TODO*** +584a81be8fddee4a8ac1d018;DeliveryNote;1389481200000|DLV000024-000107|T|***TODO*** +584a81be8fddee4a8ac1d002;DeliveryNote;1389308400000|DLV000023-000101|T|***TODO*** +584a81be8fddee4a8ac1d79e;DeliveryNote;1389654000000|DLV000144-000617|T|***TODO*** +584a81be8fddee4a8ac1d4c4;DeliveryNote;1389654000000|DLV000100-000423|T|***TODO*** +584a81be8fddee4a8ac1d49f;DeliveryNote;1390518000000|DLV000096-000414|T|***TODO*** +584a81be8fddee4a8ac1d7b4;DeliveryNote;1389135600000|DLV000145-000623|T|***TODO*** +584a81be8fddee4a8ac1d489;DeliveryNote;1390258800000|DLV000095-000408|T|***TODO*** +584a81be8fddee4a8ac1d693;DeliveryNote;1390518000000|DLV000128-000546|T|***TODO*** +584a81be8fddee4a8ac1d741;DeliveryNote;1389394800000|DLV000139-000592|T|***TODO*** +584a81be8fddee4a8ac1cfec;DeliveryNote;1389999600000|DLV000022-000095|T|***TODO*** +584a81be8fddee4a8ac1d67d;DeliveryNote;1390172400000|DLV000127-000540|T|***TODO*** +584a81be8fddee4a8ac1d469;DeliveryNote;1388876400000|DLV000092-000400|T|***TODO*** +584a81be8fddee4a8ac1d667;DeliveryNote;1389826800000|DLV000126-000534|T|***TODO*** +584a81be8fddee4a8ac1d453;DeliveryNote;1389049200000|DLV000091-000394|T|***TODO*** +584a81be8fddee4a8ac1d651;DeliveryNote;1388703600000|DLV000125-000528|T|***TODO*** +584a81be8fddee4a8ac1d43d;DeliveryNote;1388790000000|DLV000090-000388|T|***TODO*** +584a81be8fddee4a8ac1d427;DeliveryNote;1388703600000|DLV000089-000382|T|***TODO*** +584a81be8fddee4a8ac1d63b;DeliveryNote;1389135600000|DLV000124-000522|T|***TODO*** +584a81be8fddee4a8ac1d411;DeliveryNote;1388790000000|DLV000088-000376|T|***TODO*** +584a81be8fddee4a8ac1cfd6;DeliveryNote;1388790000000|DLV000021-000089|T|***TODO*** +584a81be8fddee4a8ac1d3fb;DeliveryNote;1388703600000|DLV000087-000370|T|***TODO*** +584a81be8fddee4a8ac1d3e5;DeliveryNote;1389394800000|DLV000086-000364|T|***TODO*** +584a81be8fddee4a8ac1d0c1;DeliveryNote;1389999600000|DLV000034-000152|T|***TODO*** +584a81be8fddee4a8ac1d3cf;DeliveryNote;1389913200000|DLV000085-000358|T|***TODO*** +584a81be8fddee4a8ac1cfc0;DeliveryNote;1390431600000|DLV000020-000083|T|***TODO*** +584a81be8fddee4a8ac1d3b9;DeliveryNote;1390518000000|DLV000084-000352|T|***TODO*** +584a81be8fddee4a8ac1d0dc;DeliveryNote;1390518000000|DLV000036-000159|T|***TODO*** +584a81be8fddee4a8ac1d39e;DeliveryNote;1389308400000|DLV000082-000345|T|***TODO*** +584a81be8fddee4a8ac1d72b;DeliveryNote;1388617200000|DLV000138-000586|T|***TODO*** +584a81be8fddee4a8ac1cea4;DeliveryNote;1388962800000|DLV000004-000007|T|***TODO*** +584a81be8fddee4a8ac1d064;DeliveryNote;1390258800000|DLV000029-000127|T|***TODO*** +584a81be8fddee4a8ac1cf17;DeliveryNote;1388962800000|DLV000010-000038|T|***TODO*** +584a81be8fddee4a8ac1d0f2;DeliveryNote;1389999600000|DLV000037-000165|T|***TODO*** +584a81be8fddee4a8ac1d379;DeliveryNote;1389308400000|DLV000078-000336|T|***TODO*** +584a81be8fddee4a8ac1d359;DeliveryNote;1390086000000|DLV000075-000328|T|***TODO*** +584a81be8fddee4a8ac1d33e;DeliveryNote;1388790000000|DLV000073-000321|T|***TODO*** +584a81be8fddee4a8ac1cfa5;DeliveryNote;1388876400000|DLV000018-000076|T|***TODO*** +584a81be8fddee4a8ac1d108;DeliveryNote;1389826800000|DLV000038-000171|T|***TODO*** +584a81be8fddee4a8ac1cf8f;DeliveryNote;1389308400000|DLV000017-000070|T|***TODO*** +584a81be8fddee4a8ac1d7ca;DeliveryNote;1389481200000|DLV000146-000629|T|***TODO*** +584a81be8fddee4a8ac1d328;DeliveryNote;1390086000000|DLV000072-000315|T|***TODO*** +584a81be8fddee4a8ac1ced5;DeliveryNote;1388876400000|DLV000007-000020|T|***TODO*** +584a81be8fddee4a8ac1d30d;DeliveryNote;1390431600000|DLV000070-000308|T|***TODO*** +584a81be8fddee4a8ac1cdbb;Employee;Amarillo|m|Dillion Boyce|ERP_EMP00000001|0.01|M +584a81be8fddee4a8ac1cdbe;Employee;Chesapeake|f|Ruby Bloggs|ERP_EMP00000002|0.66|M +584a81be8fddee4a8ac1cdc0;Employee;Providence|m|Devontae Donaldson|ERP_EMP00000003|0.33|M +584a81be8fddee4a8ac1cd92;Logistics;Evansville|fast distribution|ERP_LOG00000001|0.01|M +584a81be8fddee4a8ac1cd94;Logistics;Erie|quick cargo|ERP_LOG00000002|0.66|M +584a81be8fddee4a8ac1cda6;Product;fruits|short Blackcurrant|ERP_PRD00000047||8|0.33|M +584a81be8fddee4a8ac1cda7;Product;vegetables|regular Red pepper|ERP_PRD00000012|6.58||0.01|M +584a81be8fddee4a8ac1cda8;Product;fruits|violet Canary melon|ERP_PRD00000022|2.22||0.66|M +584a81be8fddee4a8ac1cda9;Product;vegetables|typical Cayenne pepper|ERP_PRD00000011|1.49||0.01|M +584a81be8fddee4a8ac1cdaa;Product;vegetables|typical Carrot|ERP_PRD00000027|0.76||0.66|M +584a81be8fddee4a8ac1cdab;Product;vegetables|light Horseradish|ERP_PRD00000016|4.13||0.01|M +584a81be8fddee4a8ac1cdac;Product;fruits|new Star fruit|ERP_PRD00000023|1.68||0.66|M +584a81be8fddee4a8ac1cdad;Product;vegetables|dark Radish|ERP_PRD00000026|1.3||0.66|M +584a81be8fddee4a8ac1cdae;Product;vegetables|big Celeriac|ERP_PRD00000036|7.4||0.33|M +584a81be8fddee4a8ac1cdaf;Product;vegetables|black Mung beans|ERP_PRD00000044|7.04||0.33|M +584a81be8fddee4a8ac1cdb0;Product;vegetables|regular Pinto beans|ERP_PRD00000013|4.66||0.01|M +584a81be8fddee4a8ac1cdb1;Product;fruits|green Jujube|ERP_PRD00000020|7.37||0.66|M +584a81be8fddee4a8ac1cdb2;Product;fruits|dark Pineapple|ERP_PRD00000001|2.96||0.01|M +584a81be8fddee4a8ac1cdb3;Product;nuts|rich Pili Nut|ERP_PRD00000007|7.47||0.01|M +584a81be8fddee4a8ac1cdb4;Product;fruits|small Pepper|ERP_PRD00000050|5.9||0.33|M +584a81be8fddee4a8ac1cdb5;Product;vegetables|red Dill|ERP_PRD00000018||8|0.66|M +584a81be8fddee4a8ac1cdb6;Product;vegetables|big Rutabaga|ERP_PRD00000019|4.9||0.66|M +584a81be8fddee4a8ac1cdb7;Product;fruits|common Jambul|ERP_PRD00000031|1.93||0.66|M +584a81be8fddee4a8ac1cdb8;Product;vegetables|dark Banana squash|ERP_PRD00000021|0.76||0.66|M +584a81be8fddee4a8ac1cdb9;Product;vegetables|typical Bok choy (known as Bok choy in UK and US)|ERP_PRD00000029|7.11||0.66|M +584a81be8fddee4a8ac1cdba;Product;fruits|typical Blackberry|ERP_PRD00000009|4.16||0.01|M +584a81be8fddee4a8ac1cdbc;Product;vegetables|regular Banana squash|ERP_PRD00000025|6.88||0.66|M +584a81be8fddee4a8ac1cdbd;Product;fruits|big Strawberry|ERP_PRD00000024|0.76||0.66|M +584a81be8fddee4a8ac1cdbf;Product;fruits|simple Satsuma|ERP_PRD00000017|8.29||0.01|M +584a81be8fddee4a8ac1cdc1;Product;fruits|black Lemon|ERP_PRD00000002|0.8||0.01|M +584a81be8fddee4a8ac1cdc2;Product;vegetables|regular Calabrese|ERP_PRD00000014|5.02||0.01|M +584a81be8fddee4a8ac1cdc3;Product;vegetables|new Wasabi|ERP_PRD00000038|3.42||0.33|M +584a81be8fddee4a8ac1cdc4;Product;fruits|original Fig|ERP_PRD00000041|9.26||0.33|M +584a81be8fddee4a8ac1cdc5;Product;vegetables|dark Oregano|ERP_PRD00000015|6.41||0.01|M +584a81be8fddee4a8ac1cdc6;Product;vegetables|regular Kale|ERP_PRD00000004|0.6||0.01|M +584a81be8fddee4a8ac1cdc7;Product;fruits|small Pomegranate|ERP_PRD00000006|4.19||0.01|M +584a81be8fddee4a8ac1cdcb;Product;nuts|round Pili Nut|ERP_PRD00000042|6.87||0.33|M +584a81be8fddee4a8ac1cdca;Product;fruits|violet Satsuma|ERP_PRD00000028|5.51||0.66|M +584a81be8fddee4a8ac1cdc9;Product;vegetables|bright Garlic|ERP_PRD00000049|7.8||0.33|M +584a81be8fddee4a8ac1cdc8;Product;fruits|usual Cranberry|ERP_PRD00000010|3.9||0.01|M +584a81be8fddee4a8ac1cd97;Product;vegetables|typical Parsley|ERP_PRD00000033|4.52||0.66|M +584a81be8fddee4a8ac1cd98;Product;fruits|violet Physalis|ERP_PRD00000039|4.75||0.33|M +584a81be8fddee4a8ac1cd99;Product;vegetables|dark Broccoflower (a hybrid)|ERP_PRD00000005|7.21||0.01|M +584a81be8fddee4a8ac1cd9a;Product;fruits|simple Plum/prune|ERP_PRD00000035|7.27||0.33|M +584a81be8fddee4a8ac1cd9b;Product;vegetables|green Celeriac|ERP_PRD00000032|2.27||0.66|M +584a81be8fddee4a8ac1cd9c;Product;fruits|big Honeydew|ERP_PRD00000034|8.94||0.66|M +584a81be8fddee4a8ac1cd9d;Product;vegetables|regular Dill|ERP_PRD00000008|2.89||0.01|M +584a81be8fddee4a8ac1cd9e;Product;fruits|rich Jambul|ERP_PRD00000046|0.85||0.33|M +584a81be8fddee4a8ac1cd9f;Product;vegetables|bright Chard|ERP_PRD00000030|5.14||0.66|M +584a81be8fddee4a8ac1cda0;Product;fruits|short Cherimoya|ERP_PRD00000003|8.85||0.01|M +584a81be8fddee4a8ac1cda1;Product;vegetables|violet Calabrese|ERP_PRD00000040|8.67||0.33|M +584a81be8fddee4a8ac1cda2;Product;vegetables|common Squashes|ERP_PRD00000043|2.97||0.33|M +584a81be8fddee4a8ac1cda3;Product;vegetables|long Basil|ERP_PRD00000037|1.72||0.33|M +584a81be8fddee4a8ac1cda4;Product;fruits|bright Kiwi fruit|ERP_PRD00000048|8.92||0.33|M +584a81be8fddee4a8ac1cda5;Product;vegetables|simple Celeriac|ERP_PRD00000045|8.3||0.33|M +584a81be8fddee4a8ac1d0a9;PurchInvoice;1390431600000|102.51||PIN000032-000146|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d78b;PurchInvoice;1389394800000|43.92||PIN000143-000612|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7a1;PurchInvoice;1389740400000|810.48||PIN000144-000618|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7b7;PurchInvoice;1389481200000|26.18||PIN000145-000624|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7cd;PurchInvoice;1389740400000|376.81||PIN000146-000630|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7e3;PurchInvoice;1389481200000|76.05||PIN000147-000636|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0c4;PurchInvoice;1390086000000|460.13||PIN000034-000153|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7fe;PurchInvoice;1389222000000|799.92||PIN000149-000643|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e483;PurchInvoice;1389999600000|-58.16||CIT_PIN000150-000002|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1e7c8;PurchInvoice;1389135600000|-57.69||CIT_PIN000151-000004|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1e832;PurchInvoice;1389308400000|-4.95||CIT_PIN000152-000006|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1e8e3;PurchInvoice;1390431600000|-115.51||CIT_PIN000153-000010|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1e8c0;PurchInvoice;1390431600000|-57.75||CIT_PIN000153-000008|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1ea66;PurchInvoice;1389308400000|-34.16||CIT_PIN000154-000012|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1eb79;PurchInvoice;1390258800000|-5.13||CIT_PIN000155-000014|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1ee15;PurchInvoice;1389049200000|-6.24||CIT_PIN000158-000018|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1eeb8;PurchInvoice;1390518000000|-60.26||CIT_PIN000159-000020|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1f047;PurchInvoice;1389394800000|-15.91||CIT_PIN000160-000022|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1f3a4;PurchInvoice;1390086000000|-20.46||CIT_PIN000161-000024|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1f662;PurchInvoice;1388876400000|-11.21||CIT_PIN000162-000026|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1fbf4;PurchInvoice;1388962800000|-5.72||CIT_PIN000163-000028|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1fca7;PurchInvoice;1388703600000|-56.1||CIT_PIN000164-000030|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1fdaa;PurchInvoice;1390172400000|-18.54||CIT_PIN000165-000032|T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d0df;PurchInvoice;1390690800000|59.7||PIN000036-000160|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0f5;PurchInvoice;1390258800000|252.28||PIN000037-000166|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d10b;PurchInvoice;1390172400000|232.44||PIN000038-000172|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf1a;PurchInvoice;1389394800000|138.6||PIN000010-000039|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d12b;PurchInvoice;1389308400000|228.34||PIN000041-000180|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d141;PurchInvoice;1388703600000|119.6||PIN000042-000186|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf30;PurchInvoice;1390086000000|581.58||PIN000011-000045|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cebd;PurchInvoice;1389222000000|71.28||PIN000005-000014|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d16b;PurchInvoice;1389135600000|256.2||PIN000047-000196|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d181;PurchInvoice;1389308400000|86.7||PIN000048-000202|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d197;PurchInvoice;1389826800000|386.24||PIN000049-000208|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1b2;PurchInvoice;1389394800000|62.4||PIN000051-000215|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf4b;PurchInvoice;1390863600000|12.18||PIN000013-000052|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1c8;PurchInvoice;1390777200000|14.41||PIN000052-000221|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1de;PurchInvoice;1390690800000|401.76||PIN000053-000227|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1f4;PurchInvoice;1389308400000|495.6||PIN000054-000233|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d20a;PurchInvoice;1390777200000|571.54||PIN000055-000239|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d220;PurchInvoice;1388876400000|694.71||PIN000056-000245|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf61;PurchInvoice;1389999600000|19.91||PIN000014-000058|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d236;PurchInvoice;1390604400000|310.2||PIN000057-000251|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d24c;PurchInvoice;1389740400000||170|PIN000058-000257|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d262;PurchInvoice;1389999600000|30.8||PIN000059-000263|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d282;PurchInvoice;1389481200000|291.48||PIN000062-000271|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf77;PurchInvoice;1389222000000|576.85||PIN000015-000064|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d298;PurchInvoice;1389567600000|106.05||PIN000063-000277|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2ae;PurchInvoice;1390777200000|277.2||PIN000064-000283|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2c4;PurchInvoice;1390604400000|46.61||PIN000065-000289|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cea7;PurchInvoice;1389308400000|16.95||PIN000004-000008|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2da;PurchInvoice;1389567600000|16.5||PIN000066-000295|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2f0;PurchInvoice;1389567600000|181.89||PIN000067-000301|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf92;PurchInvoice;1389654000000||33|PIN000017-000071|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d310;PurchInvoice;1390863600000|130.24||PIN000070-000309|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d32b;PurchInvoice;1390172400000|409.2||PIN000072-000316|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d341;PurchInvoice;1388876400000|262.24||PIN000073-000322|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfa8;PurchInvoice;1389222000000|47.67||PIN000018-000077|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d35c;PurchInvoice;1390172400000|29.36||PIN000075-000329|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1ced8;PurchInvoice;1389222000000|8.58||PIN000007-000021|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d37c;PurchInvoice;1389654000000|368.6||PIN000078-000337|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfc3;PurchInvoice;1390777200000|577.53||PIN000020-000084|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3a1;PurchInvoice;1389654000000|62.91||PIN000082-000346|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3bc;PurchInvoice;1390604400000|252.35||PIN000084-000353|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3d2;PurchInvoice;1389999600000|13.2||PIN000085-000359|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3e8;PurchInvoice;1389740400000|402.96||PIN000086-000365|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfd9;PurchInvoice;1388876400000|783.76||PIN000021-000090|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3fe;PurchInvoice;1389049200000|154.44||PIN000087-000371|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d414;PurchInvoice;1389049200000|195.75||PIN000088-000377|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d42a;PurchInvoice;1389135600000|55.32||PIN000089-000383|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d440;PurchInvoice;1388876400000|448.8||PIN000090-000389|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d456;PurchInvoice;1389394800000|298.24||PIN000091-000395|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d46c;PurchInvoice;1389222000000|56.05||PIN000092-000401|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d48c;PurchInvoice;1390518000000|543.12||PIN000095-000409|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d4a2;PurchInvoice;1390863600000|332.01||PIN000096-000415|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfef;PurchInvoice;1390172400000|29.58||PIN000022-000096|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d005;PurchInvoice;1389394800000|554.25||PIN000023-000102|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d4c7;PurchInvoice;1389740400000|139.69||PIN000100-000424|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d4f1;PurchInvoice;1389135600000|62.37||PIN000105-000434|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d507;PurchInvoice;1389135600000|660.82||PIN000106-000440|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d51d;PurchInvoice;1389913200000|400.2||PIN000107-000446|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d01b;PurchInvoice;1389567600000|141.45||PIN000024-000108|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d533;PurchInvoice;1390258800000|340.56||PIN000108-000452|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d549;PurchInvoice;1389481200000||412|PIN000109-000458|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d55f;PurchInvoice;1389308400000|57.2||PIN000110-000464|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d57a;PurchInvoice;1388962800000|23.88||PIN000112-000471|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d590;PurchInvoice;1390431600000|27.76||PIN000113-000477|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5a6;PurchInvoice;1390086000000|287.85||PIN000114-000483|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d036;PurchInvoice;1389481200000|683.1||PIN000026-000115|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5cb;PurchInvoice;1388790000000||561|PIN000118-000492|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d04c;PurchInvoice;1389049200000|388.85||PIN000027-000121|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5e6;PurchInvoice;1388790000000|501.49||PIN000120-000499|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5fc;PurchInvoice;1389135600000||466|PIN000121-000505|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d612;PurchInvoice;1389394800000|119.52||PIN000122-000511|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d628;PurchInvoice;1389135600000|335.12||PIN000123-000517|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1ceee;PurchInvoice;1389049200000|321.6||PIN000008-000027|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d63e;PurchInvoice;1389567600000|363.6||PIN000124-000523|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d654;PurchInvoice;1389135600000|319.68||PIN000125-000529|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d067;PurchInvoice;1390690800000|46.2||PIN000029-000128|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d66a;PurchInvoice;1390172400000|591.12||PIN000126-000535|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d680;PurchInvoice;1390431600000|123.6||PIN000127-000541|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf04;PurchInvoice;1389481200000|94.9||PIN000009-000033|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d696;PurchInvoice;1390690800000|188.5||PIN000128-000547|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6b1;PurchInvoice;1390518000000|46.8||PIN000130-000554|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d07d;PurchInvoice;1390086000000|21.06||PIN000030-000134|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6d1;PurchInvoice;1388876400000|277.38||PIN000133-000562|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6e7;PurchInvoice;1389654000000|288.42||PIN000134-000568|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6fd;PurchInvoice;1389740400000|255.2||PIN000135-000574|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d718;PurchInvoice;1389394800000|756.84||PIN000137-000581|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d093;PurchInvoice;1390258800000|252.72||PIN000031-000140|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d72e;PurchInvoice;1388876400000|26.52||PIN000138-000587|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d744;PurchInvoice;1389826800000|26.25||PIN000139-000593|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d75f;PurchInvoice;1389135600000|112.2||PIN000141-000600|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d775;PurchInvoice;1389999600000|330.96||PIN000142-000606|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d103;PurchOrder;1389740400000|POR000038-000170|T +584a81be8fddee4a8ac1d6c9;PurchOrder;1388703600000|POR000133-000560|T +584a81be8fddee4a8ac1d0ed;PurchOrder;1389913200000|POR000037-000164|T +584a81be8fddee4a8ac1cfd1;PurchOrder;1388703600000|POR000021-000088|T +584a81be8fddee4a8ac1cf28;PurchOrder;1389913200000|POR000011-000043|T +584a81be8fddee4a8ac1d0a1;PurchOrder;1390172400000|POR000032-000144|T +584a81be8fddee4a8ac1d354;PurchOrder;1389999600000|POR000075-000327|T +584a81be8fddee4a8ac1d08b;PurchOrder;1390086000000|POR000031-000138|T +584a81be8fddee4a8ac1d44e;PurchOrder;1389049200000|POR000091-000393|T +584a81be8fddee4a8ac1d464;PurchOrder;1388790000000|POR000092-000399|T +584a81be8fddee4a8ac1d123;PurchOrder;1389135600000|POR000041-000178|T +584a81be8fddee4a8ac1d68e;PurchOrder;1390431600000|POR000128-000545|T +584a81be8fddee4a8ac1d7db;PurchOrder;1389308400000|POR000147-000634|T +584a81be8fddee4a8ac1d5c3;PurchOrder;1388617200000|POR000118-000490|T +584a81be8fddee4a8ac1d05f;PurchOrder;1390258800000|POR000029-000126|T +584a81be8fddee4a8ac1cfe7;PurchOrder;1389913200000|POR000022-000094|T +584a81be8fddee4a8ac1d218;PurchOrder;1388703600000|POR000056-000243|T +584a81be8fddee4a8ac1d484;PurchOrder;1390172400000|POR000095-000407|T +584a81be8fddee4a8ac1d2a6;PurchOrder;1390345200000|POR000064-000281|T +584a81be8fddee4a8ac1d044;PurchOrder;1388703600000|POR000027-000119|T +584a81be8fddee4a8ac1d64c;PurchOrder;1388703600000|POR000125-000527|T +584a81be8fddee4a8ac1d02e;PurchOrder;1389222000000|POR000026-000113|T +584a81be8fddee4a8ac1d163;PurchOrder;1388703600000|POR000047-000194|T +584a81be8fddee4a8ac1d59e;PurchOrder;1389913200000|POR000114-000481|T +584a81be8fddee4a8ac1d374;PurchOrder;1389222000000|POR000078-000335|T +584a81be8fddee4a8ac1cefc;PurchOrder;1389222000000|POR000009-000031|T +584a81be8fddee4a8ac1d49a;PurchOrder;1390431600000|POR000096-000413|T +584a81be8fddee4a8ac1d202;PurchOrder;1390345200000|POR000055-000237|T +584a81be8fddee4a8ac1d1ec;PurchOrder;1389135600000|POR000054-000231|T +584a81be8fddee4a8ac1ced0;PurchOrder;1388876400000|POR000007-000019|T +584a81be8fddee4a8ac1d7f6;PurchOrder;1388790000000|POR000149-000641|T +584a81be8fddee4a8ac1cee6;PurchOrder;1388703600000|POR000008-000025|T +584a81be8fddee4a8ac1cfa0;PurchOrder;1388790000000|POR000018-000075|T +584a81be8fddee4a8ac1d179;PurchOrder;1389135600000|POR000048-000200|T +584a81be8fddee4a8ac1d588;PurchOrder;1389999600000|POR000113-000475|T +584a81be8fddee4a8ac1d25a;PurchOrder;1389567600000|POR000059-000261|T +584a81be8fddee4a8ac1d572;PurchOrder;1388703600000|POR000112-000469|T +584a81be8fddee4a8ac1d4bf;PurchOrder;1389567600000|POR000100-000422|T +584a81be8fddee4a8ac1d557;PurchOrder;1388876400000|POR000110-000462|T +584a81be8fddee4a8ac1ceb5;PurchOrder;1388962800000|POR000005-000012|T +584a81be8fddee4a8ac1cffd;PurchOrder;1389222000000|POR000023-000100|T +584a81be8fddee4a8ac1d013;PurchOrder;1389394800000|POR000024-000106|T +584a81be8fddee4a8ac1d541;PurchOrder;1389049200000|POR000109-000456|T +584a81be8fddee4a8ac1d290;PurchOrder;1389308400000|POR000063-000275|T +584a81be8fddee4a8ac1d4e9;PurchOrder;1388790000000|POR000105-000432|T +584a81be8fddee4a8ac1d52b;PurchOrder;1389826800000|POR000108-000450|T +584a81be8fddee4a8ac1d308;PurchOrder;1390431600000|POR000070-000307|T +584a81be8fddee4a8ac1d1d6;PurchOrder;1390431600000|POR000053-000225|T +584a81be8fddee4a8ac1cf6f;PurchOrder;1389049200000|POR000015-000062|T +584a81be8fddee4a8ac1d399;PurchOrder;1389222000000|POR000082-000344|T +584a81be8fddee4a8ac1d6df;PurchOrder;1389481200000|POR000134-000566|T +584a81be8fddee4a8ac1d6a9;PurchOrder;1390345200000|POR000130-000552|T +584a81be8fddee4a8ac1d2bc;PurchOrder;1390345200000|POR000065-000287|T +584a81be8fddee4a8ac1d4ff;PurchOrder;1388876400000|POR000106-000438|T +584a81be8fddee4a8ac1d515;PurchOrder;1389740400000|POR000107-000444|T +584a81be8fddee4a8ac1d6f5;PurchOrder;1389308400000|POR000135-000572|T +584a81be8fddee4a8ac1d757;PurchOrder;1388703600000|POR000141-000598|T +584a81be8fddee4a8ac1d1c0;PurchOrder;1390345200000|POR000052-000219|T +584a81be8fddee4a8ac1d139;PurchOrder;1388530800000|POR000042-000184|T +584a81be8fddee4a8ac1cf43;PurchOrder;1390431600000|POR000013-000050|T +584a81be8fddee4a8ac1d3b4;PurchOrder;1390431600000|POR000084-000351|T +584a81be8fddee4a8ac1d0d7;PurchOrder;1390431600000|POR000036-000158|T +584a81be8fddee4a8ac1d73c;PurchOrder;1389394800000|POR000139-000591|T +584a81be8fddee4a8ac1cfbb;PurchOrder;1390345200000|POR000020-000082|T +584a81be8fddee4a8ac1d1aa;PurchOrder;1388962800000|POR000051-000213|T +584a81be8fddee4a8ac1cf8a;PurchOrder;1389222000000|POR000017-000069|T +584a81be8fddee4a8ac1d18f;PurchOrder;1389567600000|POR000049-000206|T +584a81be8fddee4a8ac1d244;PurchOrder;1389308400000|POR000058-000255|T +584a81be8fddee4a8ac1d075;PurchOrder;1389913200000|POR000030-000132|T +584a81be8fddee4a8ac1d3ca;PurchOrder;1389826800000|POR000085-000357|T +584a81be8fddee4a8ac1d7c5;PurchOrder;1389394800000|POR000146-000628|T +584a81be8fddee4a8ac1cf12;PurchOrder;1388962800000|POR000010-000037|T +584a81be8fddee4a8ac1d0bc;PurchOrder;1389913200000|POR000034-000151|T +584a81be8fddee4a8ac1d799;PurchOrder;1389567600000|POR000144-000616|T +584a81be8fddee4a8ac1d76d;PurchOrder;1389567600000|POR000142-000604|T +584a81be8fddee4a8ac1d636;PurchOrder;1389135600000|POR000124-000521|T +584a81be8fddee4a8ac1d323;PurchOrder;1389999600000|POR000072-000314|T +584a81be8fddee4a8ac1d3e0;PurchOrder;1389394800000|POR000086-000363|T +584a81be8fddee4a8ac1d3f6;PurchOrder;1388617200000|POR000087-000369|T +584a81be8fddee4a8ac1d22e;PurchOrder;1390172400000|POR000057-000249|T +584a81be8fddee4a8ac1d27a;PurchOrder;1389049200000|POR000062-000269|T +584a81be8fddee4a8ac1d620;PurchOrder;1388790000000|POR000123-000515|T +584a81be8fddee4a8ac1d662;PurchOrder;1389740400000|POR000126-000533|T +584a81be8fddee4a8ac1ce9f;PurchOrder;1388876400000|POR000004-000006|T +584a81be8fddee4a8ac1d783;PurchOrder;1388962800000|POR000143-000610|T +584a81be8fddee4a8ac1d60a;PurchOrder;1389135600000|POR000122-000509|T +584a81be8fddee4a8ac1d726;PurchOrder;1388530800000|POR000138-000585|T +584a81be8fddee4a8ac1d2d2;PurchOrder;1389135600000|POR000066-000293|T +584a81be8fddee4a8ac1d40c;PurchOrder;1388703600000|POR000088-000375|T +584a81be8fddee4a8ac1cf59;PurchOrder;1389826800000|POR000014-000056|T +584a81be8fddee4a8ac1d422;PurchOrder;1388703600000|POR000089-000381|T +584a81be8fddee4a8ac1d710;PurchOrder;1389135600000|POR000137-000579|T +584a81be8fddee4a8ac1d7af;PurchOrder;1389049200000|POR000145-000622|T +584a81be8fddee4a8ac1d5f4;PurchOrder;1388876400000|POR000121-000503|T +584a81be8fddee4a8ac1d2e8;PurchOrder;1389135600000|POR000067-000299|T +584a81be8fddee4a8ac1d339;PurchOrder;1388703600000|POR000073-000320|T +584a81be8fddee4a8ac1d5de;PurchOrder;1388530800000|POR000120-000497|T +584a81be8fddee4a8ac1d678;PurchOrder;1390086000000|POR000127-000539|T +584a81be8fddee4a8ac1d438;PurchOrder;1388703600000|POR000090-000387|T +584a81be8fddee4a8ac1d2c6;SalesInvoice;1390431600000|SIN000065-000290|47.79||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2dc;SalesInvoice;1388962800000|SIN000066-000296|17.49||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2f2;SalesInvoice;1389049200000|SIN000067-000302|185.76||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d12d;SalesInvoice;1389222000000|SIN000041-000181|237.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf94;SalesInvoice;1389308400000|SIN000017-000072|37.05||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d312;SalesInvoice;1390431600000|SIN000070-000310|130.24||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf1c;SalesInvoice;1389049200000|SIN000010-000040|158.76||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7b9;SalesInvoice;1388876400000|SIN000145-000625|27.54||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d32d;SalesInvoice;1390172400000|SIN000072-000317|417.26||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d10d;SalesInvoice;1389740400000|SIN000038-000173|256.36||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d343;SalesInvoice;1388530800000|SIN000073-000323|266.64||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d698;SalesInvoice;1390518000000|SIN000128-000548|188.5||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d746;SalesInvoice;1389567600000|SIN000139-000594||28|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0f7;SalesInvoice;1389999600000|SIN000037-000167|257.32||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d35e;SalesInvoice;1390172400000|SIN000075-000330|30.52||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfaa;SalesInvoice;1388703600000|SIN000018-000078|51.52||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d37e;SalesInvoice;1389308400000|SIN000078-000338|413.44||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cfc5;SalesInvoice;1390431600000|SIN000020-000085|577.53||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6b3;SalesInvoice;1390345200000|SIN000130-000555|48.6||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3a3;SalesInvoice;1389222000000|SIN000082-000347|68.13||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0e1;SalesInvoice;1390258800000|SIN000036-000161|59.7||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3be;SalesInvoice;1390518000000|SIN000084-000354|256.76||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3d4;SalesInvoice;1389913200000|SIN000085-000360|12.94||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d3ea;SalesInvoice;1389567600000|SIN000086-000366|427.34||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1ceda;SalesInvoice;1388962800000|SIN000007-000022|8.91||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0c6;SalesInvoice;1389999600000|SIN000034-000154|460.13||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d400;SalesInvoice;1388617200000|SIN000087-000372|160.92||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d416;SalesInvoice;1388703600000|SIN000088-000378|219.24||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1fdf0;SalesInvoice;1390518000000|CIT_SIN000166-000033|-37.7||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1fda7;SalesInvoice;1390172400000|CIT_SIN000165-000031|-12.12||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d42c;SalesInvoice;1388790000000|SIN000089-000384|62.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6d3;SalesInvoice;1388617200000|SIN000133-000563|282.9||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d442;SalesInvoice;1388790000000|SIN000090-000390|457.64||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1fca0;SalesInvoice;1388703600000|CIT_SIN000164-000029|-28.6||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1cfdb;SalesInvoice;1388617200000|SIN000021-000091|845.84||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1fbe8;SalesInvoice;1388962800000|CIT_SIN000163-000027|-6.29||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d458;SalesInvoice;1389135600000|SIN000091-000396|309.76||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1f657;SalesInvoice;1388876400000|CIT_SIN000162-000025|-2.95||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d7a3;SalesInvoice;1389654000000|SIN000144-000619|842.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d46e;SalesInvoice;1388876400000|SIN000092-000402|58.9||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1f3a2;SalesInvoice;1390086000000|CIT_SIN000161-000023|-41.73||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1f043;SalesInvoice;1389394800000|CIT_SIN000160-000021|-10.82||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1cff1;SalesInvoice;1389999600000|SIN000022-000097|31.28||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d48e;SalesInvoice;1390258800000|SIN000095-000410|565.44||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d4a4;SalesInvoice;1390258800000|SIN000096-000416|332.01||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6e9;SalesInvoice;1389394800000|SIN000134-000569|282.48||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1eeb4;SalesInvoice;1390518000000|CIT_SIN000159-000019|-21.3||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1ee10;SalesInvoice;1389049200000|CIT_SIN000158-000017|-9.73||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d4c9;SalesInvoice;1389394800000|SIN000100-000425|147.62||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1ecf4;SalesInvoice;1388617200000|CIT_SIN000157-000016|-12.44||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d007;SalesInvoice;1389222000000|SIN000023-000103|554.25||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d4f3;SalesInvoice;1388876400000|SIN000105-000435|67.23||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1ebc4;SalesInvoice;1389999600000|CIT_SIN000156-000015|-69.02||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1eb77;SalesInvoice;1390258800000|CIT_SIN000155-000013|-10.05||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1ea5a;SalesInvoice;1389308400000|CIT_SIN000154-000011|-71.01||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d509;SalesInvoice;1388876400000|SIN000106-000441|673.4||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d01d;SalesInvoice;1389308400000|SIN000024-000109|147.19||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e8dd;SalesInvoice;1390431600000|CIT_SIN000153-000009|-57.75||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d51f;SalesInvoice;1389567600000|SIN000107-000447|400.2||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d535;SalesInvoice;1389999600000|SIN000108-000453|368.08||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d07f;SalesInvoice;1389826800000|SIN000030-000135|21.87||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e8b9;SalesInvoice;1390431600000|CIT_SIN000153-000007|-115.51||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1cf06;SalesInvoice;1389394800000|SIN000009-000034|102.57||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e828;SalesInvoice;1389308400000|CIT_SIN000152-000005|-3.71||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d54b;SalesInvoice;1389135600000|SIN000109-000459||445|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e7c6;SalesInvoice;1389135600000|CIT_SIN000151-000003|-31.13||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d561;SalesInvoice;1388962800000|SIN000110-000465|62.92||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1e479;SalesInvoice;1389999600000|CIT_SIN000150-000001|-60.51||T|*** TODO @ ComplaintHandling *** +584a81be8fddee4a8ac1d800;SalesInvoice;1388876400000|SIN000149-000644|847.44||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d57c;SalesInvoice;1388790000000|SIN000112-000472|25.68||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d6ff;SalesInvoice;1389308400000|SIN000135-000575|281.6||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d592;SalesInvoice;1390086000000|SIN000113-000478|28.84||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d095;SalesInvoice;1390172400000|SIN000031-000141|257.66||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d038;SalesInvoice;1389308400000|SIN000026-000116|710.1||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5a8;SalesInvoice;1389826800000|SIN000114-000484|304.38||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d78d;SalesInvoice;1388876400000|SIN000143-000613|44.64||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d777;SalesInvoice;1389481200000|SIN000142-000607|337.68||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5cd;SalesInvoice;1388790000000|SIN000118-000493|572.05||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d761;SalesInvoice;1388790000000|SIN000141-000601|125.46||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cef0;SalesInvoice;1388790000000|SIN000008-000028|333.6||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5e8;SalesInvoice;1388530800000|SIN000120-000500|520.89||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d71a;SalesInvoice;1389222000000|SIN000137-000582|771.96||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7e5;SalesInvoice;1389308400000|SIN000147-000637|83.46||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5fe;SalesInvoice;1389049200000|SIN000121-000506||502|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d614;SalesInvoice;1389222000000|SIN000122-000512|129.6||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d04e;SalesInvoice;1388617200000|SIN000027-000122|418.88||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d7cf;SalesInvoice;1389308400000|SIN000146-000631|384.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d62a;SalesInvoice;1388876400000|SIN000123-000518|354.59||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d0ab;SalesInvoice;1390258800000|SIN000032-000147|100.5||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d640;SalesInvoice;1389049200000|SIN000124-000524|392.4||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf4d;SalesInvoice;1390431600000|SIN000013-000053|12.18||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1b4;SalesInvoice;1389049200000|SIN000051-000216|64.87||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d730;SalesInvoice;1388530800000|SIN000138-000588|28.22||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d199;SalesInvoice;1389654000000|SIN000049-000209|416.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d069;SalesInvoice;1390258800000|SIN000029-000129|51.03||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1ca;SalesInvoice;1390345200000|SIN000052-000222|15.07||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1e0;SalesInvoice;1390518000000|SIN000053-000228|426.06||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d656;SalesInvoice;1388790000000|SIN000125-000530|359.52||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d1f6;SalesInvoice;1389222000000|SIN000054-000234|495.6||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d183;SalesInvoice;1389135600000|SIN000048-000203|89.76||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf63;SalesInvoice;1389913200000|SIN000014-000059|20.24||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d20c;SalesInvoice;1390345200000|SIN000055-000240|594.5||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d222;SalesInvoice;1388790000000|SIN000056-000246|736.56||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cea9;SalesInvoice;1388962800000|SIN000004-000009|18.3||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d238;SalesInvoice;1390172400000|SIN000057-000252|329.34||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d16d;SalesInvoice;1388876400000|SIN000047-000197|271.45||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d24e;SalesInvoice;1389308400000|SIN000058-000258||184|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d264;SalesInvoice;1389654000000|SIN000059-000264|33.32||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf32;SalesInvoice;1389999600000|SIN000011-000046|605.07||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cf79;SalesInvoice;1389135600000|SIN000015-000065|622.5||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d284;SalesInvoice;1388962800000|SIN000062-000272|314.58||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d66c;SalesInvoice;1389740400000|SIN000126-000536|626.4||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d143;SalesInvoice;1388530800000|SIN000042-000187|124.4||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1cebf;SalesInvoice;1388962800000|SIN000005-000015|72.16||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d29a;SalesInvoice;1389222000000|SIN000063-000278|108.15||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d2b0;SalesInvoice;1390518000000|SIN000064-000284||294|T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d682;SalesInvoice;1390172400000|SIN000127-000542|121.2||T|*** TODO @ Brokerage *** +584a81be8fddee4a8ac1d5ef;SalesOrder;1388790000000|1389135600000|SOR000121-000502|T +584a81be8fddee4a8ac1d7aa;SalesOrder;1388876400000|1389222000000|SOR000145-000621|T +584a81be8fddee4a8ac1d605;SalesOrder;1388962800000|1389222000000|SOR000122-000508|T +584a81be8fddee4a8ac1ceb0;SalesOrder;1388962800000|1389308400000|SOR000005-000011|T +584a81be8fddee4a8ac1d407;SalesOrder;1388530800000|1388876400000|SOR000088-000374|T +584a81be8fddee4a8ac1d0b7;SalesOrder;1389740400000|1389913200000|SOR000034-000150|T +584a81be8fddee4a8ac1d23f;SalesOrder;1389135600000|1389481200000|SOR000058-000254|T +584a81be8fddee4a8ac1d2cd;SalesOrder;1388962800000|1389308400000|SOR000066-000292|T +584a81be8fddee4a8ac1d7c0;SalesOrder;1389222000000|1389567600000|SOR000146-000627|T +584a81be8fddee4a8ac1cef7;SalesOrder;1389135600000|1389394800000|SOR000009-000030|T +584a81be8fddee4a8ac1d6c4;SalesOrder;1388530800000|1388790000000|SOR000133-000559|T +584a81be8fddee4a8ac1d61b;SalesOrder;1388617200000|1388962800000|SOR000123-000514|T +584a81be8fddee4a8ac1d255;SalesOrder;1389394800000|1389740400000|SOR000059-000260|T +584a81be8fddee4a8ac1d3f1;SalesOrder;1388617200000|1388962800000|SOR000087-000368|T +584a81be8fddee4a8ac1d3db;SalesOrder;1389308400000|1389654000000|SOR000086-000362|T +584a81be8fddee4a8ac1cf23;SalesOrder;1389740400000|1389913200000|SOR000011-000042|T +584a81be8fddee4a8ac1d0d2;SalesOrder;1390258800000|1390604400000|SOR000036-000157|T +584a81be8fddee4a8ac1d631;SalesOrder;1389049200000|1389394800000|SOR000124-000520|T +584a81be8fddee4a8ac1d65d;SalesOrder;1389567600000|1389913200000|SOR000126-000532|T +584a81be8fddee4a8ac1d3c5;SalesOrder;1389654000000|1389999600000|SOR000085-000356|T +584a81be8fddee4a8ac1d303;SalesOrder;1390258800000|1390518000000|SOR000070-000306|T +584a81be8fddee4a8ac1d1a5;SalesOrder;1388790000000|1388962800000|SOR000051-000212|T +584a81be8fddee4a8ac1d05a;SalesOrder;1390086000000|1390431600000|SOR000029-000125|T +584a81be8fddee4a8ac1d721;SalesOrder;1388530800000|1388876400000|SOR000138-000584|T +584a81be8fddee4a8ac1d3af;SalesOrder;1390258800000|1390518000000|SOR000084-000350|T +584a81be8fddee4a8ac1d737;SalesOrder;1389308400000|1389567600000|SOR000139-000590|T +584a81be8fddee4a8ac1d18a;SalesOrder;1389394800000|1389740400000|SOR000049-000205|T +584a81be8fddee4a8ac1cf6a;SalesOrder;1388876400000|1389049200000|SOR000015-000061|T +584a81be8fddee4a8ac1d134;SalesOrder;1388530800000|1388876400000|SOR000042-000183|T +584a81be8fddee4a8ac1cfb6;SalesOrder;1390172400000|1390345200000|SOR000020-000081|T +584a81be8fddee4a8ac1d1bb;SalesOrder;1390258800000|1390518000000|SOR000052-000218|T +584a81be8fddee4a8ac1d275;SalesOrder;1388962800000|1389308400000|SOR000062-000268|T +584a81be8fddee4a8ac1cecb;SalesOrder;1388703600000|1388962800000|SOR000007-000018|T +584a81be8fddee4a8ac1d394;SalesOrder;1389222000000|1389567600000|SOR000082-000343|T +584a81be8fddee4a8ac1cf3e;SalesOrder;1390258800000|1390518000000|SOR000013-000049|T +584a81be8fddee4a8ac1d36f;SalesOrder;1389049200000|1389394800000|SOR000078-000334|T +584a81be8fddee4a8ac1d1d1;SalesOrder;1390258800000|1390431600000|SOR000053-000224|T +584a81be8fddee4a8ac1d2a1;SalesOrder;1390258800000|1390604400000|SOR000064-000280|T +584a81be8fddee4a8ac1d647;SalesOrder;1388530800000|1388790000000|SOR000125-000526|T +584a81be8fddee4a8ac1d2b7;SalesOrder;1390258800000|1390604400000|SOR000065-000286|T +584a81be8fddee4a8ac1d4fa;SalesOrder;1388876400000|1389222000000|SOR000106-000437|T +584a81be8fddee4a8ac1cf54;SalesOrder;1389740400000|1390086000000|SOR000014-000055|T +584a81be8fddee4a8ac1d1e7;SalesOrder;1388962800000|1389222000000|SOR000054-000230|T +584a81be8fddee4a8ac1d2e3;SalesOrder;1389049200000|1389394800000|SOR000067-000298|T +584a81be8fddee4a8ac1ce9a;SalesOrder;1388703600000|1389049200000|SOR000004-000005|T +584a81be8fddee4a8ac1d526;SalesOrder;1389740400000|1390086000000|SOR000108-000449|T +584a81be8fddee4a8ac1d6da;SalesOrder;1389308400000|1389654000000|SOR000134-000565|T +584a81be8fddee4a8ac1d6a4;SalesOrder;1390172400000|1390431600000|SOR000130-000551|T +584a81be8fddee4a8ac1d768;SalesOrder;1389394800000|1389654000000|SOR000142-000603|T +584a81be8fddee4a8ac1d00e;SalesOrder;1389222000000|1389567600000|SOR000024-000105|T +584a81be8fddee4a8ac1d0e8;SalesOrder;1389740400000|1389999600000|SOR000037-000163|T +584a81be8fddee4a8ac1d53c;SalesOrder;1388962800000|1389308400000|SOR000109-000455|T +584a81be8fddee4a8ac1d086;SalesOrder;1389913200000|1390172400000|SOR000031-000137|T +584a81be8fddee4a8ac1d4e4;SalesOrder;1388617200000|1388962800000|SOR000105-000431|T +584a81be8fddee4a8ac1d552;SalesOrder;1388703600000|1388876400000|SOR000110-000461|T +584a81be8fddee4a8ac1cff8;SalesOrder;1389135600000|1389481200000|SOR000023-000099|T +584a81be8fddee4a8ac1d174;SalesOrder;1389135600000|1389481200000|SOR000048-000199|T +584a81be8fddee4a8ac1d1fd;SalesOrder;1390172400000|1390518000000|SOR000055-000236|T +584a81be8fddee4a8ac1d6f0;SalesOrder;1389222000000|1389567600000|SOR000135-000571|T +584a81be8fddee4a8ac1d510;SalesOrder;1389567600000|1389913200000|SOR000107-000443|T +584a81be8fddee4a8ac1cee1;SalesOrder;1388530800000|1388876400000|SOR000008-000024|T +584a81be8fddee4a8ac1d4ba;SalesOrder;1389394800000|1389740400000|SOR000100-000421|T +584a81be8fddee4a8ac1cf9b;SalesOrder;1388617200000|1388962800000|SOR000018-000074|T +584a81be8fddee4a8ac1d7f1;SalesOrder;1388617200000|1388876400000|SOR000149-000640|T +584a81be8fddee4a8ac1d56d;SalesOrder;1388530800000|1388876400000|SOR000112-000468|T +584a81be8fddee4a8ac1d213;SalesOrder;1388530800000|1388876400000|SOR000056-000242|T +584a81be8fddee4a8ac1d673;SalesOrder;1389913200000|1390172400000|SOR000127-000538|T +584a81be8fddee4a8ac1d583;SalesOrder;1389999600000|1390345200000|SOR000113-000474|T +584a81be8fddee4a8ac1d34f;SalesOrder;1389913200000|1390258800000|SOR000075-000326|T +584a81be8fddee4a8ac1d070;SalesOrder;1389826800000|1390172400000|SOR000030-000131|T +584a81be8fddee4a8ac1d752;SalesOrder;1388530800000|1388876400000|SOR000141-000597|T +584a81be8fddee4a8ac1d15e;SalesOrder;1388703600000|1389049200000|SOR000047-000193|T +584a81be8fddee4a8ac1d029;SalesOrder;1389049200000|1389222000000|SOR000026-000112|T +584a81be8fddee4a8ac1d334;SalesOrder;1388530800000|1388876400000|SOR000073-000319|T +584a81be8fddee4a8ac1d77e;SalesOrder;1388790000000|1389135600000|SOR000143-000609|T +584a81be8fddee4a8ac1d599;SalesOrder;1389740400000|1390086000000|SOR000114-000480|T +584a81be8fddee4a8ac1d31e;SalesOrder;1389913200000|1390172400000|SOR000072-000313|T +584a81be8fddee4a8ac1d689;SalesOrder;1390258800000|1390431600000|SOR000128-000544|T +584a81be8fddee4a8ac1d495;SalesOrder;1390258800000|1390604400000|SOR000096-000412|T +584a81be8fddee4a8ac1d09c;SalesOrder;1389999600000|1390172400000|SOR000032-000143|T +584a81be8fddee4a8ac1d47f;SalesOrder;1389999600000|1390258800000|SOR000095-000406|T +584a81be8fddee4a8ac1d794;SalesOrder;1389394800000|1389654000000|SOR000144-000615|T +584a81be8fddee4a8ac1d45f;SalesOrder;1388617200000|1388790000000|SOR000092-000398|T +584a81be8fddee4a8ac1cfe2;SalesOrder;1389740400000|1390086000000|SOR000022-000093|T +584a81be8fddee4a8ac1d229;SalesOrder;1389999600000|1390345200000|SOR000057-000248|T +584a81be8fddee4a8ac1d28b;SalesOrder;1389135600000|1389308400000|SOR000063-000274|T +584a81be8fddee4a8ac1d7d6;SalesOrder;1389308400000|1389654000000|SOR000147-000633|T +584a81be8fddee4a8ac1d5be;SalesOrder;1388530800000|1388876400000|SOR000118-000489|T +584a81be8fddee4a8ac1d70b;SalesOrder;1389049200000|1389394800000|SOR000137-000578|T +584a81be8fddee4a8ac1cf85;SalesOrder;1389049200000|1389222000000|SOR000017-000068|T +584a81be8fddee4a8ac1d449;SalesOrder;1388876400000|1389135600000|SOR000091-000392|T +584a81be8fddee4a8ac1d5d9;SalesOrder;1388530800000|1388876400000|SOR000120-000496|T +584a81be8fddee4a8ac1cf0d;SalesOrder;1388790000000|1389135600000|SOR000010-000036|T +584a81be8fddee4a8ac1d0fe;SalesOrder;1389567600000|1389913200000|SOR000038-000169|T +584a81be8fddee4a8ac1d433;SalesOrder;1388530800000|1388876400000|SOR000090-000386|T +584a81be8fddee4a8ac1d41d;SalesOrder;1388530800000|1388876400000|SOR000089-000380|T +584a81be8fddee4a8ac1d11e;SalesOrder;1388962800000|1389222000000|SOR000041-000177|T +584a81be8fddee4a8ac1cfcc;SalesOrder;1388530800000|1388876400000|SOR000021-000087|T +584a81be8fddee4a8ac1d03f;SalesOrder;1388530800000|1388876400000|SOR000027-000118|T +584a81be8fddee4a8ac1ce87;SalesQuotation;1388530800000|SQN000001-000001|T +584a81be8fddee4a8ac1ce8c;SalesQuotation;1388530800000|SQN000002-000002|T +584a81be8fddee4a8ac1ce91;SalesQuotation;1388530800000|SQN000003-000003|T +584a81be8fddee4a8ac1ce96;SalesQuotation;1388530800000|SQN000004-000004|T +584a81be8fddee4a8ac1ceac;SalesQuotation;1388530800000|SQN000005-000010|T +584a81be8fddee4a8ac1cec2;SalesQuotation;1388530800000|SQN000006-000016|T +584a81be8fddee4a8ac1cec7;SalesQuotation;1388530800000|SQN000007-000017|T +584a81be8fddee4a8ac1cedd;SalesQuotation;1388530800000|SQN000008-000023|T +584a81be8fddee4a8ac1cef3;SalesQuotation;1388530800000|SQN000009-000029|T +584a81be8fddee4a8ac1cf09;SalesQuotation;1388530800000|SQN000010-000035|T +584a81be8fddee4a8ac1cf1f;SalesQuotation;1388530800000|SQN000011-000041|T +584a81be8fddee4a8ac1cf35;SalesQuotation;1388530800000|SQN000012-000047|T +584a81be8fddee4a8ac1cf3a;SalesQuotation;1388530800000|SQN000013-000048|T +584a81be8fddee4a8ac1cf50;SalesQuotation;1388530800000|SQN000014-000054|T +584a81be8fddee4a8ac1cf66;SalesQuotation;1388530800000|SQN000015-000060|T +584a81be8fddee4a8ac1cf7c;SalesQuotation;1388530800000|SQN000016-000066|T +584a81be8fddee4a8ac1cf81;SalesQuotation;1388530800000|SQN000017-000067|T +584a81be8fddee4a8ac1cf97;SalesQuotation;1388530800000|SQN000018-000073|T +584a81be8fddee4a8ac1cfad;SalesQuotation;1388530800000|SQN000019-000079|T +584a81be8fddee4a8ac1cfb2;SalesQuotation;1388530800000|SQN000020-000080|T +584a81be8fddee4a8ac1cfc8;SalesQuotation;1388530800000|SQN000021-000086|T +584a81be8fddee4a8ac1cfde;SalesQuotation;1388530800000|SQN000022-000092|T +584a81be8fddee4a8ac1cff4;SalesQuotation;1388530800000|SQN000023-000098|T +584a81be8fddee4a8ac1d00a;SalesQuotation;1388530800000|SQN000024-000104|T +584a81be8fddee4a8ac1d020;SalesQuotation;1388530800000|SQN000025-000110|T +584a81be8fddee4a8ac1d025;SalesQuotation;1388530800000|SQN000026-000111|T +584a81be8fddee4a8ac1d03b;SalesQuotation;1388530800000|SQN000027-000117|T +584a81be8fddee4a8ac1d051;SalesQuotation;1388530800000|SQN000028-000123|T +584a81be8fddee4a8ac1d056;SalesQuotation;1388530800000|SQN000029-000124|T +584a81be8fddee4a8ac1d06c;SalesQuotation;1388530800000|SQN000030-000130|T +584a81be8fddee4a8ac1d082;SalesQuotation;1388530800000|SQN000031-000136|T +584a81be8fddee4a8ac1d098;SalesQuotation;1388530800000|SQN000032-000142|T +584a81be8fddee4a8ac1d0ae;SalesQuotation;1388530800000|SQN000033-000148|T +584a81be8fddee4a8ac1d0b3;SalesQuotation;1388530800000|SQN000034-000149|T +584a81be8fddee4a8ac1d0c9;SalesQuotation;1388530800000|SQN000035-000155|T +584a81be8fddee4a8ac1d0ce;SalesQuotation;1388530800000|SQN000036-000156|T +584a81be8fddee4a8ac1d0e4;SalesQuotation;1388530800000|SQN000037-000162|T +584a81be8fddee4a8ac1d0fa;SalesQuotation;1388530800000|SQN000038-000168|T +584a81be8fddee4a8ac1d110;SalesQuotation;1388530800000|SQN000039-000174|T +584a81be8fddee4a8ac1d115;SalesQuotation;1388530800000|SQN000040-000175|T +584a81be8fddee4a8ac1d11a;SalesQuotation;1388530800000|SQN000041-000176|T +584a81be8fddee4a8ac1d130;SalesQuotation;1388530800000|SQN000042-000182|T +584a81be8fddee4a8ac1d146;SalesQuotation;1388530800000|SQN000043-000188|T +584a81be8fddee4a8ac1d14b;SalesQuotation;1388530800000|SQN000044-000189|T +584a81be8fddee4a8ac1d150;SalesQuotation;1388530800000|SQN000045-000190|T +584a81be8fddee4a8ac1d155;SalesQuotation;1388530800000|SQN000046-000191|T +584a81be8fddee4a8ac1d15a;SalesQuotation;1388530800000|SQN000047-000192|T +584a81be8fddee4a8ac1d170;SalesQuotation;1388530800000|SQN000048-000198|T +584a81be8fddee4a8ac1d186;SalesQuotation;1388530800000|SQN000049-000204|T +584a81be8fddee4a8ac1d19c;SalesQuotation;1388530800000|SQN000050-000210|T +584a81be8fddee4a8ac1d1a1;SalesQuotation;1388530800000|SQN000051-000211|T +584a81be8fddee4a8ac1d1b7;SalesQuotation;1388530800000|SQN000052-000217|T +584a81be8fddee4a8ac1d1cd;SalesQuotation;1388530800000|SQN000053-000223|T +584a81be8fddee4a8ac1d1e3;SalesQuotation;1388530800000|SQN000054-000229|T +584a81be8fddee4a8ac1d1f9;SalesQuotation;1388530800000|SQN000055-000235|T +584a81be8fddee4a8ac1d20f;SalesQuotation;1388530800000|SQN000056-000241|T +584a81be8fddee4a8ac1d225;SalesQuotation;1388530800000|SQN000057-000247|T +584a81be8fddee4a8ac1d23b;SalesQuotation;1388530800000|SQN000058-000253|T +584a81be8fddee4a8ac1d251;SalesQuotation;1388530800000|SQN000059-000259|T +584a81be8fddee4a8ac1d267;SalesQuotation;1388530800000|SQN000060-000265|T +584a81be8fddee4a8ac1d26c;SalesQuotation;1388530800000|SQN000061-000266|T +584a81be8fddee4a8ac1d271;SalesQuotation;1388530800000|SQN000062-000267|T +584a81be8fddee4a8ac1d287;SalesQuotation;1388530800000|SQN000063-000273|T +584a81be8fddee4a8ac1d29d;SalesQuotation;1388530800000|SQN000064-000279|T +584a81be8fddee4a8ac1d2b3;SalesQuotation;1388530800000|SQN000065-000285|T +584a81be8fddee4a8ac1d2c9;SalesQuotation;1388530800000|SQN000066-000291|T +584a81be8fddee4a8ac1d2df;SalesQuotation;1388530800000|SQN000067-000297|T +584a81be8fddee4a8ac1d2f5;SalesQuotation;1388530800000|SQN000068-000303|T +584a81be8fddee4a8ac1d2fa;SalesQuotation;1388530800000|SQN000069-000304|T +584a81be8fddee4a8ac1d2ff;SalesQuotation;1388530800000|SQN000070-000305|T +584a81be8fddee4a8ac1d315;SalesQuotation;1388530800000|SQN000071-000311|T +584a81be8fddee4a8ac1d31a;SalesQuotation;1388530800000|SQN000072-000312|T +584a81be8fddee4a8ac1d330;SalesQuotation;1388530800000|SQN000073-000318|T +584a81be8fddee4a8ac1d346;SalesQuotation;1388530800000|SQN000074-000324|T +584a81be8fddee4a8ac1d34b;SalesQuotation;1388530800000|SQN000075-000325|T +584a81be8fddee4a8ac1d361;SalesQuotation;1388530800000|SQN000076-000331|T +584a81be8fddee4a8ac1d366;SalesQuotation;1388530800000|SQN000077-000332|T +584a81be8fddee4a8ac1d36b;SalesQuotation;1388530800000|SQN000078-000333|T +584a81be8fddee4a8ac1d381;SalesQuotation;1388530800000|SQN000079-000339|T +584a81be8fddee4a8ac1d386;SalesQuotation;1388530800000|SQN000080-000340|T +584a81be8fddee4a8ac1d38b;SalesQuotation;1388530800000|SQN000081-000341|T +584a81be8fddee4a8ac1d390;SalesQuotation;1388530800000|SQN000082-000342|T +584a81be8fddee4a8ac1d3a6;SalesQuotation;1388530800000|SQN000083-000348|T +584a81be8fddee4a8ac1d3ab;SalesQuotation;1388530800000|SQN000084-000349|T +584a81be8fddee4a8ac1d3c1;SalesQuotation;1388530800000|SQN000085-000355|T +584a81be8fddee4a8ac1d3d7;SalesQuotation;1388530800000|SQN000086-000361|T +584a81be8fddee4a8ac1d3ed;SalesQuotation;1388530800000|SQN000087-000367|T +584a81be8fddee4a8ac1d403;SalesQuotation;1388530800000|SQN000088-000373|T +584a81be8fddee4a8ac1d419;SalesQuotation;1388530800000|SQN000089-000379|T +584a81be8fddee4a8ac1d42f;SalesQuotation;1388530800000|SQN000090-000385|T +584a81be8fddee4a8ac1d445;SalesQuotation;1388530800000|SQN000091-000391|T +584a81be8fddee4a8ac1d45b;SalesQuotation;1388530800000|SQN000092-000397|T +584a81be8fddee4a8ac1d471;SalesQuotation;1388530800000|SQN000093-000403|T +584a81be8fddee4a8ac1d476;SalesQuotation;1388530800000|SQN000094-000404|T +584a81be8fddee4a8ac1d47b;SalesQuotation;1388530800000|SQN000095-000405|T +584a81be8fddee4a8ac1d491;SalesQuotation;1388530800000|SQN000096-000411|T +584a81be8fddee4a8ac1d4a7;SalesQuotation;1388530800000|SQN000097-000417|T +584a81be8fddee4a8ac1d4ac;SalesQuotation;1388530800000|SQN000098-000418|T +584a81be8fddee4a8ac1d4b1;SalesQuotation;1388530800000|SQN000099-000419|T +584a81be8fddee4a8ac1d4b6;SalesQuotation;1388530800000|SQN000100-000420|T +584a81be8fddee4a8ac1d4cc;SalesQuotation;1388530800000|SQN000101-000426|T +584a81be8fddee4a8ac1d4d1;SalesQuotation;1388530800000|SQN000102-000427|T +584a81be8fddee4a8ac1d4d6;SalesQuotation;1388530800000|SQN000103-000428|T +584a81be8fddee4a8ac1d4db;SalesQuotation;1388530800000|SQN000104-000429|T +584a81be8fddee4a8ac1d4e0;SalesQuotation;1388530800000|SQN000105-000430|T +584a81be8fddee4a8ac1d4f6;SalesQuotation;1388530800000|SQN000106-000436|T +584a81be8fddee4a8ac1d50c;SalesQuotation;1388530800000|SQN000107-000442|T +584a81be8fddee4a8ac1d522;SalesQuotation;1388530800000|SQN000108-000448|T +584a81be8fddee4a8ac1d538;SalesQuotation;1388530800000|SQN000109-000454|T +584a81be8fddee4a8ac1d54e;SalesQuotation;1388530800000|SQN000110-000460|T +584a81be8fddee4a8ac1d564;SalesQuotation;1388530800000|SQN000111-000466|T +584a81be8fddee4a8ac1d569;SalesQuotation;1388530800000|SQN000112-000467|T +584a81be8fddee4a8ac1d57f;SalesQuotation;1388530800000|SQN000113-000473|T +584a81be8fddee4a8ac1d595;SalesQuotation;1388530800000|SQN000114-000479|T +584a81be8fddee4a8ac1d5ab;SalesQuotation;1388530800000|SQN000115-000485|T +584a81be8fddee4a8ac1d5b0;SalesQuotation;1388530800000|SQN000116-000486|T +584a81be8fddee4a8ac1d5b5;SalesQuotation;1388530800000|SQN000117-000487|T +584a81be8fddee4a8ac1d5ba;SalesQuotation;1388530800000|SQN000118-000488|T +584a81be8fddee4a8ac1d5d0;SalesQuotation;1388530800000|SQN000119-000494|T +584a81be8fddee4a8ac1d5d5;SalesQuotation;1388530800000|SQN000120-000495|T +584a81be8fddee4a8ac1d5eb;SalesQuotation;1388530800000|SQN000121-000501|T +584a81be8fddee4a8ac1d601;SalesQuotation;1388530800000|SQN000122-000507|T +584a81be8fddee4a8ac1d617;SalesQuotation;1388530800000|SQN000123-000513|T +584a81be8fddee4a8ac1d62d;SalesQuotation;1388530800000|SQN000124-000519|T +584a81be8fddee4a8ac1d643;SalesQuotation;1388530800000|SQN000125-000525|T +584a81be8fddee4a8ac1d659;SalesQuotation;1388530800000|SQN000126-000531|T +584a81be8fddee4a8ac1d66f;SalesQuotation;1388530800000|SQN000127-000537|T +584a81be8fddee4a8ac1d685;SalesQuotation;1388530800000|SQN000128-000543|T +584a81be8fddee4a8ac1d69b;SalesQuotation;1388530800000|SQN000129-000549|T +584a81be8fddee4a8ac1d6a0;SalesQuotation;1388530800000|SQN000130-000550|T +584a81be8fddee4a8ac1d6b6;SalesQuotation;1388530800000|SQN000131-000556|T +584a81be8fddee4a8ac1d6bb;SalesQuotation;1388530800000|SQN000132-000557|T +584a81be8fddee4a8ac1d6c0;SalesQuotation;1388530800000|SQN000133-000558|T +584a81be8fddee4a8ac1d6d6;SalesQuotation;1388530800000|SQN000134-000564|T +584a81be8fddee4a8ac1d6ec;SalesQuotation;1388530800000|SQN000135-000570|T +584a81be8fddee4a8ac1d702;SalesQuotation;1388530800000|SQN000136-000576|T +584a81be8fddee4a8ac1d707;SalesQuotation;1388530800000|SQN000137-000577|T +584a81be8fddee4a8ac1d71d;SalesQuotation;1388530800000|SQN000138-000583|T +584a81be8fddee4a8ac1d733;SalesQuotation;1388530800000|SQN000139-000589|T +584a81be8fddee4a8ac1d749;SalesQuotation;1388530800000|SQN000140-000595|T +584a81be8fddee4a8ac1d74e;SalesQuotation;1388530800000|SQN000141-000596|T +584a81be8fddee4a8ac1d764;SalesQuotation;1388530800000|SQN000142-000602|T +584a81be8fddee4a8ac1d77a;SalesQuotation;1388530800000|SQN000143-000608|T +584a81be8fddee4a8ac1d790;SalesQuotation;1388530800000|SQN000144-000614|T +584a81be8fddee4a8ac1d7a6;SalesQuotation;1388530800000|SQN000145-000620|T +584a81be8fddee4a8ac1d7bc;SalesQuotation;1388530800000|SQN000146-000626|T +584a81be8fddee4a8ac1d7d2;SalesQuotation;1388530800000|SQN000147-000632|T +584a81be8fddee4a8ac1d7e8;SalesQuotation;1388530800000|SQN000148-000638|T +584a81be8fddee4a8ac1d7ed;SalesQuotation;1388530800000|SQN000149-000639|T +584a81be8fddee4a8ac1d803;SalesQuotation;1388530800000|SQN000150-000645|T +584a81be8fddee4a8ac1ee8d;Ticket;1390518000000|584a81be8fddee4a8ac1d1d1|late delivery|T +584a81be8fddee4a8ac1f62a;Ticket;1388876400000|584a81be8fddee4a8ac1d45f|late delivery|T +584a81be8fddee4a8ac1e8a6;Ticket;1390431600000|584a81be8fddee4a8ac1cfb6|bad quality|T +584a81be8fddee4a8ac1fc8e;Ticket;1388703600000|584a81be8fddee4a8ac1d5be|bad quality|T +584a81be8fddee4a8ac1ede6;Ticket;1389049200000|584a81be8fddee4a8ac1d1a5|late delivery|T +584a81be8fddee4a8ac1e8c5;Ticket;1390431600000|584a81be8fddee4a8ac1cfb6|late delivery|T +584a81be8fddee4a8ac1e7b3;Ticket;1389135600000|584a81be8fddee4a8ac1cf6a|late delivery|T +584a81be8fddee4a8ac1e815;Ticket;1389308400000|584a81be8fddee4a8ac1cf85|late delivery|T +584a81be8fddee4a8ac1fde0;Ticket;1390518000000|584a81be8fddee4a8ac1d689|late delivery|T +584a81be8fddee4a8ac1ecd6;Ticket;1388617200000|584a81be8fddee4a8ac1d134|bad quality|T +584a81be8fddee4a8ac1f370;Ticket;1390086000000|584a81be8fddee4a8ac1d31e|bad quality|T +584a81be8fddee4a8ac1fbc4;Ticket;1388962800000|584a81be8fddee4a8ac1d552|late delivery|T +584a81be8fddee4a8ac1ebb3;Ticket;1389999600000|584a81be8fddee4a8ac1d0b7|late delivery|T +584a81be8fddee4a8ac1fd96;Ticket;1390172400000|584a81be8fddee4a8ac1d673|bad quality|T +584a81be8fddee4a8ac1eb52;Ticket;1390258800000|584a81be8fddee4a8ac1d09c|late delivery|T +584a81be8fddee4a8ac1f019;Ticket;1389394800000|584a81be8fddee4a8ac1d28b|late delivery|T +584a81be8fddee4a8ac1e43d;Ticket;1389999600000|584a81be8fddee4a8ac1cf23|late delivery|T +584a81be8fddee4a8ac1ea2f;Ticket;1389308400000|584a81be8fddee4a8ac1d029|late delivery|T +584a81be8fddee4a8ac1fde5;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1e449;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1e7bd;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1e7c0;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1e81e;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1e818;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1e8b0;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1e8c7;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1e8ac;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1ea39;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1ea40;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1eb59;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1ebba;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1ebb5;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1ece6;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1ecd9;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1edf9;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1edee;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1ee99;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1f027;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1f02d;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1f37e;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1f386;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1f640;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1f647;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1fbcf;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1fc91;User;Amarillo|dillion.boyce@biiig.org|584a81be8fddee4a8ac1cdbb|m|Dillion Boyce|CIT_USE00000001|0.01|M +584a81be8fddee4a8ac1fc96;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1fd98;User;Providence|devontae.donaldson@biiig.org|584a81be8fddee4a8ac1cdc0|m|Devontae Donaldson|CIT_USE00000003|0.33|M +584a81be8fddee4a8ac1fd9d;User;Chesapeake|ruby.bloggs@biiig.org|584a81be8fddee4a8ac1cdbe|f|Ruby Bloggs|CIT_USE00000002|0.66|M +584a81be8fddee4a8ac1cdce;Vendor;Pompano Beach|reasonable supplier|ERP_VEN00000002|0.66|M +584a81be8fddee4a8ac1cdcc;Vendor;Fayetteville|exclusive supplier|ERP_VEN00000001|0.01|M +584a81be8fddee4a8ac1cdcd;Vendor;Providence|reasonable trader|ERP_VEN00000003|0.33|M diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties new file mode 100644 index 000000000000..78891926e038 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties @@ -0,0 +1 @@ +since,9 \ No newline at end of file diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties_by_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties_by_label new file mode 100644 index 000000000000..126cdfecd918 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_edge_properties_by_label @@ -0,0 +1,2 @@ +knows,since,6 +hasModerator,since,3 \ No newline at end of file diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count new file mode 100644 index 000000000000..45a4fb75db86 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count @@ -0,0 +1 @@ +8 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count_by_edge_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count_by_edge_label new file mode 100644 index 000000000000..c8e05da14da2 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_source_vertex_count_by_edge_label @@ -0,0 +1,5 @@ +hasInterest,4 +hasModerator,2 +knows,6 +hasTag,2 +hasMember,2 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count new file mode 100644 index 000000000000..7f8f011eb73d --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count @@ -0,0 +1 @@ +7 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count_by_edge_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count_by_edge_label new file mode 100644 index 000000000000..bba8e266562b --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_target_vertex_count_by_edge_label @@ -0,0 +1,5 @@ +hasInterest,2 +hasModerator,2 +knows,4 +hasMember,4 +hasTag,3 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties new file mode 100644 index 000000000000..8fec68bb59ec --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties @@ -0,0 +1,7 @@ +name,9 +gender,2 +city,3 +age,4 +speaks,1 +locIP,1 +title,2 \ No newline at end of file diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties_by_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties_by_label new file mode 100644 index 000000000000..fee1364c5213 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/distinct_vertex_properties_by_label @@ -0,0 +1,8 @@ +Person,name,6 +Person,gender,2 +Person,city,3 +Person,age,4 +Person,speaks,1 +Person,locIP,1 +Tag,name,3 +Forum,title,2 \ No newline at end of file diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count new file mode 100644 index 000000000000..a45fd52cc589 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count @@ -0,0 +1 @@ +24 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_label new file mode 100644 index 000000000000..374c3a206563 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_label @@ -0,0 +1,5 @@ +hasInterest,4 +hasModerator,2 +knows,10 +hasTag,4 +hasMember,4 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_source_vertex_and_edge_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_source_vertex_and_edge_label new file mode 100644 index 000000000000..d9d723e8e0f3 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_source_vertex_and_edge_label @@ -0,0 +1,5 @@ +Forum,hasMember,4 +Forum,hasModerator,2 +Forum,hasTag,4 +Person,hasInterest,4 +Person,knows,10 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_target_vertex_and_edge_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_target_vertex_and_edge_label new file mode 100644 index 000000000000..31c0c4fdfe40 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/edge_count_by_target_vertex_and_edge_label @@ -0,0 +1,5 @@ +Tag,hasTag,4 +Tag,hasInterest,4 +Person,knows,10 +Person,hasMember,4 +Person,hasModerator,2 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/incoming_vertex_degree_distribution b/gradoop-examples/src/main/resources/data/csv/sna/statistics/incoming_vertex_degree_distribution new file mode 100644 index 000000000000..1ddb7c38f1e7 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/incoming_vertex_degree_distribution @@ -0,0 +1,4 @@ +2,4 +3,2 +0,3 +5,2 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/outgoing_vertex_degree_distribution b/gradoop-examples/src/main/resources/data/csv/sna/statistics/outgoing_vertex_degree_distribution new file mode 100644 index 000000000000..03c0599343fd --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/outgoing_vertex_degree_distribution @@ -0,0 +1,4 @@ +3,2 +0,3 +5,2 +2,4 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count new file mode 100644 index 000000000000..b4de39476753 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count @@ -0,0 +1 @@ +11 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count_by_label b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count_by_label new file mode 100644 index 000000000000..d31d53ccc9e8 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_count_by_label @@ -0,0 +1,3 @@ +Person,6 +Forum,2 +Tag,3 diff --git a/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_degree_distribution b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_degree_distribution new file mode 100644 index 000000000000..e4813c6883c8 --- /dev/null +++ b/gradoop-examples/src/main/resources/data/csv/sna/statistics/vertex_degree_distribution @@ -0,0 +1,4 @@ +3,4 +2,1 +5,2 +6,4 diff --git a/gradoop-flink/pom.xml b/gradoop-flink/pom.xml index 0c04f6c3eebc..31aa20a79a39 100644 --- a/gradoop-flink/pom.xml +++ b/gradoop-flink/pom.xml @@ -5,7 +5,7 @@ org.gradoop gradoop-parent - 0.5.0-SNAPSHOT + 0.4.1 gradoop-flink @@ -108,6 +108,10 @@ + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRank.java b/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRank.java index b43b1b013b04..4ab251d026ee 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRank.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRank.java @@ -24,6 +24,7 @@ import org.gradoop.flink.algorithms.gelly.functions.EdgeToGellyEdgeWithNullValue; import org.gradoop.flink.algorithms.gelly.functions.VertexToGellyVertexWithNullValue; import org.gradoop.flink.algorithms.gelly.pagerank.functions.PageRankToAttribute; +import org.gradoop.flink.algorithms.gelly.pagerank.functions.PageRankResultKey; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.functions.epgm.Id; @@ -69,7 +70,7 @@ protected LogicalGraph executeInGelly(Graph gra dampingFactor, iterations) .run(graph) .join(currentGraph.getVertices()) - .where(0) + .where(new PageRankResultKey()) .equalTo(new Id<>()) .with(new PageRankToAttribute(propertyKey)); return currentGraph.getConfig().getLogicalGraphFactory().fromDataSets(newVertices, diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/functions/PageRankResultKey.java b/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/functions/PageRankResultKey.java new file mode 100644 index 000000000000..718fc8a550e2 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/algorithms/gelly/pagerank/functions/PageRankResultKey.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.algorithms.gelly.pagerank.functions; + +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.graph.library.linkanalysis.PageRank; +import org.gradoop.common.model.impl.id.GradoopId; + +/** + * Select the vertex id of an Page Rank result. + */ +public class PageRankResultKey implements KeySelector, GradoopId> { + + @Override + public GradoopId getKey(PageRank.Result result) throws Exception { + return result.getVertexId0(); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/csv/metadata/MetaDataParser.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/csv/metadata/MetaDataParser.java index d37c3e464223..cd5044ae7d46 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/csv/metadata/MetaDataParser.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/csv/metadata/MetaDataParser.java @@ -77,6 +77,8 @@ private static Map> getTypeParserMap() { map.put(TypeString.LOCALDATE.getTypeString(), LocalDate::parse); map.put(TypeString.LOCALTIME.getTypeString(), LocalTime::parse); map.put(TypeString.LOCALDATETIME.getTypeString(), LocalDateTime::parse); + map.put(TypeString.NULL.getTypeString(), MetaDataParser::parseNullProperty); + map.put(TypeString.SET.getTypeString(), MetaDataParser::parseSetProperty); return Collections.unmodifiableMap(map); } @@ -104,6 +106,11 @@ public static MetaData create(List> metaDataStrin // it's a list with one additional data type (type of list items) propertyMetaDataList.add(new PropertyMetaData( propertyMetadata[0], propertyMetadata[1], getListValueParser(propertyTypeTokens[1]))); + } else if (propertyTypeTokens.length == 2 && + propertyTypeTokens[0].equals(TypeString.SET.getTypeString())) { + // it's a set with one additional data type (type of set items) + propertyMetaDataList.add(new PropertyMetaData( + propertyMetadata[0], propertyMetadata[1], getSetValueParser(propertyTypeTokens[1]))); } else if (propertyTypeTokens.length == 3 && propertyTypeTokens[0].equals(TypeString.MAP.getTypeString())) { // it's a map with two additional data types (key type + value type) @@ -210,6 +217,21 @@ private static Function getMapValueParser(String keyType, String ); } + /** + * Creates a parsing function for set property type. + * + * @param setItemType string representation of the set item type, e.g. "String" + * @return parsing function + */ + private static Function getSetValueParser(String setItemType) { + final String itemType = setItemType.toLowerCase(); + // check the validity of the set item type + if (!TYPE_PARSER_MAP.containsKey(itemType)) { + throw new TypeNotPresentException(itemType, null); + } + + return s -> parseSetProperty(s, TYPE_PARSER_MAP.get(itemType)); + } /** * Parse function to translate string representation of a List to a list of PropertyValues * Every PropertyValue has the type "string", because there is no parser for the items given @@ -284,6 +306,51 @@ private static Object parseMapProperty( .collect(Collectors.toMap(e -> PropertyValue.create(e[0]), e -> PropertyValue.create(e[1]))); } + /** + * Parse function to translate string representation of a Set to a set of PropertyValues + * Every PropertyValue has the type "string", because there is no parser for the items given + * Use {@link #parseListProperty(String, Function)} to specify a parsing function + * + * @param s the string to parse as set, e.g. "[myString1, myString2]" + * @return the set represented by the argument + */ + private static Object parseSetProperty(String s) { + // no item type given, so use string as type + s = s.replace("[", "").replace("]", ""); + return Arrays.stream(s.split(LIST_DELIMITER)) + .map(PropertyValue::create) + .collect(Collectors.toSet()); + } + + /** + * Parse function to translate string representation of a Set to a set of PropertyValues + * + * @param s the string to parse as set, e.g. "[myString1, myString2]" + * @param itemParser the function to parse the set items + * @return the set represented by the argument + */ + private static Object parseSetProperty(String s, Function itemParser) { + s = s.replace("[", "").replace("]", ""); + return Arrays.stream(s.split(LIST_DELIMITER)) + .map(itemParser) + .map(PropertyValue::create) + .collect(Collectors.toSet()); + } + /** + * Parse function to create null from the null string representation. + * + * @param nullString The string representing null. + * @throws IllegalArgumentException The string that is passed has to represent null. + * @return Returns null + */ + private static Object parseNullProperty(String nullString) throws IllegalArgumentException { + if (nullString != null && nullString.equalsIgnoreCase(TypeString.NULL.getTypeString())) { + return null; + } else { + throw new IllegalArgumentException("Only null represents a null string."); + } + } + /** * Returns the type string for the specified property value. * @@ -291,7 +358,9 @@ private static Object parseMapProperty( * @return property type string */ public static String getTypeString(PropertyValue propertyValue) { - if (propertyValue.isShort()) { + if (propertyValue.isNull()) { + return TypeString.NULL.getTypeString(); + } else if (propertyValue.isShort()) { return TypeString.SHORT.getTypeString(); } else if (propertyValue.isInt()) { return TypeString.INTEGER.getTypeString(); @@ -327,6 +396,11 @@ public static String getTypeString(PropertyValue propertyValue) { return TypeString.LOCALTIME.getTypeString(); } else if (propertyValue.isDateTime()) { return TypeString.LOCALDATETIME.getTypeString(); + } else if (propertyValue.isSet()) { + // set type string is set:{itemType} + return TypeString.SET.getTypeString() + + PROPERTY_TOKEN_DELIMITER + + getTypeString(propertyValue.getSet().iterator().next()); } else { throw new IllegalArgumentException("Type " + propertyValue.getType() + " is not supported"); } @@ -336,6 +410,10 @@ public static String getTypeString(PropertyValue propertyValue) { * Supported type strings for the CSV format. */ private enum TypeString { + /** + * Null type + */ + NULL("null"), /** * Boolean type */ @@ -391,7 +469,11 @@ private enum TypeString { /** * LocalDateTime type */ - LOCALDATETIME("localdatetime"); + LOCALDATETIME("localdatetime"), + /** + * Set type + */ + SET("set"); /** * String representation diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/dot/DOTDataSink.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/dot/DOTDataSink.java index bb65404895a0..0ee682b1c748 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/dot/DOTDataSink.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/dot/DOTDataSink.java @@ -71,9 +71,9 @@ public void write(LogicalGraph graph, boolean overwrite) throws IOException { } @Override - public void write(GraphCollection graphCollection, boolean overWrite) throws IOException { + public void write(GraphCollection graphCollection, boolean overwrite) throws IOException { FileSystem.WriteMode writeMode = - overWrite ? FileSystem.WriteMode.OVERWRITE : FileSystem.WriteMode.NO_OVERWRITE; + overwrite ? FileSystem.WriteMode.OVERWRITE : FileSystem.WriteMode.NO_OVERWRITE; DOTFileFormat dotFileFormat = new DOTFileFormat(graphInformation); GraphvizWriter graphvizWriter = new GraphvizWriter(new Path(path)); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLConsoleOutput.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLConsoleOutput.java new file mode 100644 index 000000000000..729c9f4ee271 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLConsoleOutput.java @@ -0,0 +1,70 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.io.impl.gdl; + +import org.apache.flink.api.java.io.LocalCollectionOutputFormat; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.flink.model.api.epgm.GraphCollection; +import org.gradoop.flink.model.api.epgm.GraphCollectionFactory; +import org.gradoop.flink.model.api.epgm.LogicalGraph; + +import java.util.ArrayList; +import java.util.List; + +/** + * Allows to print graphs and graph collections to the standard output. + */ +public class GDLConsoleOutput { + + /** + * Prints the logical graph to the standard output. + * + * @param logicalGraph The logical graph that is supposed to be printed. + * @throws Exception Forwarded from flink execute. + */ + public static void print(LogicalGraph logicalGraph) throws Exception { + GraphCollectionFactory collectionFactory = logicalGraph.getConfig().getGraphCollectionFactory(); + GraphCollection graphCollection = collectionFactory.fromGraph(logicalGraph); + + print(graphCollection); + } + + /** + * Prints the graph collection to the standard output. + * + * @param graphCollection The graph collection that is supposed to be printed. + * @throws Exception Forwarded from flink execute. + */ + public static void print(GraphCollection graphCollection) throws Exception { + List graphHeads = new ArrayList<>(); + graphCollection.getGraphHeads().output(new LocalCollectionOutputFormat<>(graphHeads)); + + List vertices = new ArrayList<>(); + graphCollection.getVertices().output(new LocalCollectionOutputFormat<>(vertices)); + + List edges = new ArrayList<>(); + graphCollection.getEdges().output(new LocalCollectionOutputFormat<>(edges)); + + graphCollection.getConfig().getExecutionEnvironment().execute(); + + GDLEncoder encoder = new GDLEncoder(graphHeads, vertices, edges); + String graphString = encoder.getGDLString(); + + System.out.println(graphString); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLDataSink.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLDataSink.java new file mode 100644 index 000000000000..0e20179ca0c9 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLDataSink.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.io.impl.gdl; + +import org.apache.flink.api.java.io.TextOutputFormat; +import org.apache.flink.core.fs.FileSystem; +import org.apache.flink.core.fs.Path; +import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.impl.gdl.functions.GraphTransactionsToGDL; +import org.gradoop.flink.model.api.epgm.GraphCollection; +import org.gradoop.flink.model.api.epgm.LogicalGraph; + +import java.io.IOException; + +/** + * A data sink that writes a graph or graph collection to a gdl formatted string. + * It is executed with a parallelism of 1, and therefore limited to smaller graphs. + */ +public class GDLDataSink implements DataSink { + + /** + * The path to write the file to. + */ + private String path; + + /** + * Creates a GDL data sink. + * + * @param path The path to write the file to. + */ + public GDLDataSink(String path) { + this.path = path; + } + + /** + * {@inheritDoc} + */ + @Override + public void write(LogicalGraph logicalGraph) throws IOException { + write(logicalGraph, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(GraphCollection graphCollection) throws IOException { + write(graphCollection, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(LogicalGraph graph, boolean overwrite) throws IOException { + write(graph.getConfig().getGraphCollectionFactory().fromGraph(graph), overwrite); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(GraphCollection graphCollection, boolean overwrite) throws IOException { + FileSystem.WriteMode writeMode = + overwrite ? FileSystem.WriteMode.OVERWRITE : FileSystem.WriteMode.NO_OVERWRITE; + + TextOutputFormat textOutputFormat = new TextOutputFormat<>(new Path(path)); + textOutputFormat.setWriteMode(writeMode); + + graphCollection + .getGraphTransactions() + .reduceGroup(new GraphTransactionsToGDL()) + .output(textOutputFormat) + .setParallelism(1); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLEncoder.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLEncoder.java new file mode 100644 index 000000000000..44bc4918f863 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/GDLEncoder.java @@ -0,0 +1,331 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.io.impl.gdl; + +import org.gradoop.common.model.impl.id.GradoopId; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.Properties; +import org.gradoop.common.model.impl.properties.Property; +import org.gradoop.common.model.impl.properties.PropertyValue; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Encodes data structures using the GDL format. + */ +public class GDLEncoder { + /** + * Marks the beginning of the definition of vertices and edges. + */ + private static final String GRAPH_ELEMENTS_DEFINITION_START = "["; + /** + * Marks the end of the definition of vertices and edges. + */ + private static final String GRAPH_ELEMENTS_DEFINITION_END = "]"; + /** + * graph variable prefix + */ + private static final String GRAPH_VARIABLE_PREFIX = "g"; + /** + * vertex variable prefix + */ + private static final String VERTEX_VARIABLE_PREFIX = "v"; + /** + * edge variable prefix + */ + private static final String EDGE_VARIABLE_PREFIX = "e"; + /** + * Marks the end of the properties prefix. + */ + private static final String PROPERTIES_PREFIX = "{"; + /** + * Marks the end of the properties string. + */ + private static final String PROPERTIES_SUFFIX = "}"; + /** + * Separates properties. + */ + private static final String PROPERTIES_SEPARATOR = ","; + /** + * Separates key and value for properties. + */ + private static final String KEY_VALUE_SEPARATOR = ":"; + /** + * Suffix for GDL double representation. + */ + private static final String DOUBLE_SUFFIX = "d"; + /** + * Suffix for GDL float representation. + */ + private static final String FLOAT_SUFFIX = "f"; + /** + * Suffix for GDL long representation. + */ + private static final String LONG_SUFFIX = "L"; + /** + * GDL null representation. + */ + private static final String NULL_STRING = "NULL"; + /** + * GDL string prefix + */ + private static final String STRING_PREFIX = "\""; + /** + * GDL string suffix + */ + private static final String STRING_SUFFIX = "\""; + + /** + * Graph head to encode. + */ + private List graphHeads; + /** + * Vertices to encode. + */ + private List vertices; + /** + * Edges to encode. + */ + private List edges; + + /** + * Creates a GDLEncoder using the passed parameters. + * + * @param graphHeads graph head that should be encoded + * @param vertices vertices that should be encoded + * @param edges edges that should be encoded + */ + public GDLEncoder(List graphHeads, List vertices, List edges) { + this.graphHeads = graphHeads; + this.vertices = vertices; + this.edges = edges; + } + + /** + * Creates a GDL formatted string from the graph heads, vertices and edges. + * + * @return GDL formatted string + */ + public String getGDLString() { + Map idToGraphHeadName = getGraphHeadNameMapping(graphHeads); + Map idToVertexName = getVertexNameMapping(vertices); + Map idToEdgeName = getEdgeNameMapping(edges); + + Set usedVertexIds = new HashSet<>(); + Set usedEdgeIds = new HashSet<>(); + + StringBuilder result = new StringBuilder(); + + for (GraphHead gh : graphHeads) { + StringBuilder verticesString = new StringBuilder(); + StringBuilder edgesString = new StringBuilder(); + + for (Vertex v : vertices) { + Boolean containedInGraph = v.getGraphIds().contains(gh.getId()); + Boolean firstOccurrence = !usedVertexIds.contains(v.getId()); + + if (containedInGraph && firstOccurrence) { + String vertexString = vertexToGDLString(v, idToVertexName); + usedVertexIds.add(v.getId()); + verticesString.append(vertexString).append(System.lineSeparator()); + } + } + + for (Edge e : edges) { + if (e.getGraphIds().contains(gh.getId())) { + Boolean firstOccurrence = !usedEdgeIds.contains(e.getId()); + String edgeString = edgeToGDLString(e, idToVertexName, idToEdgeName, firstOccurrence); + usedEdgeIds.add(e.getId()); + edgesString.append(edgeString).append(System.lineSeparator()); + } + } + + result + .append(graphHeadToGDLString(gh, idToGraphHeadName)) + .append(GRAPH_ELEMENTS_DEFINITION_START).append(System.lineSeparator()) + .append(verticesString).append(System.lineSeparator()) + .append(edgesString) + .append(GRAPH_ELEMENTS_DEFINITION_END) + .append(System.lineSeparator()).append(System.lineSeparator()); + } + return result.toString(); + } + + /** + * Returns a mapping between the graph heads gradoop ids and the GDL variable names. + * + * @param graphHeads The graph heads. + * @return Mapping between graph head and GDL variable name. + */ + private Map getGraphHeadNameMapping(List graphHeads) { + Map idToGraphHeadName = new HashMap<>(graphHeads.size()); + for (int i = 0; i < graphHeads.size(); i++) { + GraphHead g = graphHeads.get(i); + String gName = String.format("%s%s", GRAPH_VARIABLE_PREFIX, i); + idToGraphHeadName.put(g.getId(), gName); + } + return idToGraphHeadName; + } + + /** + * Returns a mapping between the vertex GradoopID and the GDL variable name. + * + * @param vertices The graph vertices. + * @return Mapping between vertex and GDL variable name. + */ + private Map getVertexNameMapping(List vertices) { + Map idToVertexName = new HashMap<>(vertices.size()); + for (int i = 0; i < vertices.size(); i++) { + Vertex v = vertices.get(i); + String vName = String.format("%s_%s_%s", VERTEX_VARIABLE_PREFIX, v.getLabel(), i); + idToVertexName.put(v.getId(), vName); + } + return idToVertexName; + } + + /** + * Returns a mapping between the edge GradoopId and the GDL variable name. + * + * @param edges The graph edges. + * @return Mapping between edge and GDL variable name. + */ + private Map getEdgeNameMapping(List edges) { + Map idToEdgeName = new HashMap<>(edges.size()); + for (int i = 0; i < edges.size(); i++) { + Edge e = edges.get(i); + String eName = String.format("%s_%s_%s", EDGE_VARIABLE_PREFIX, e.getLabel(), i); + idToEdgeName.put(e.getId(), eName); + } + return idToEdgeName; + } + + /** + * Returns a GDL formatted graph head string. + * + * @param g graph head + * @param idToGraphHeadName mapping from graph head id to its GDL variable name + * @return GDL formatted string + */ + private String graphHeadToGDLString(GraphHead g, Map idToGraphHeadName) { + return String.format("%s:%s %s", + idToGraphHeadName.get(g.getId()), + g.getLabel(), + propertiesToGDLString(g.getProperties())); + } + + /** + * Returns the gdl formatted vertex including the properties and the label on first occurrence + * or otherwise just the variable name. + * + * @param v The vertex that should be formatted. + * @param idToVertexName Maps GradoopId of a vertex to a string that represents the gdl + * variable name + * @return A GDL formatted vertex string. + */ + private String vertexToGDLString(Vertex v, Map idToVertexName) { + return String.format("(%s:%s %s)", + idToVertexName.get(v.getId()), + v.getLabel(), + propertiesToGDLString(v.getProperties())); + } + + /** + * Returns the GDL formatted edge, including the properties and the label on first occurrence + * or otherwise just the variable name. + * + * @param e The edge to be formatted. + * @param idToVertexName Maps GradoopId of a vertex to a string that represents the GDL + * variable name + * @param idToEdgeName Maps GradoopId of an edge to a string that represents the GDL variable + * name. + * @param firstOccurrence Is it the first occurrence of the vertex in all graphs? + * @return A GDL formatted edge string. + */ + private String edgeToGDLString( + Edge e, + Map idToVertexName, + Map idToEdgeName, + Boolean firstOccurrence) { + String result; + if (firstOccurrence) { + result = String.format("(%s)-[%s:%s%s]->(%s)", + idToVertexName.get(e.getSourceId()), + idToEdgeName.get(e.getId()), + e.getLabel(), + propertiesToGDLString(e.getProperties()), + idToVertexName.get(e.getTargetId())); + } else { + result = String.format("(%s)-[%s]->(%s)", + idToVertexName.get(e.getSourceId()), + idToEdgeName.get(e.getId()), + idToVertexName.get(e.getTargetId())); + } + return result; + } + + /** + * Returns the properties as a GDL formatted String. + * + * @param properties The properties to be formatted. + * @return A GDL formatted string that represents the properties. + */ + private String propertiesToGDLString(Properties properties) { + if (properties == null || properties.isEmpty()) { + return ""; + } else { + return properties.toList().stream() + .map(this::propertyToGDLString) + .collect(Collectors.joining(PROPERTIES_SEPARATOR, PROPERTIES_PREFIX, PROPERTIES_SUFFIX)); + } + } + + /** + * Returns this property as a GDL formatted String. + * + * @param property The property. + * @return A GDL formatted string that represents the property. + */ + private String propertyToGDLString(Property property) { + StringBuilder result = new StringBuilder() + .append(property.getKey()) + .append(KEY_VALUE_SEPARATOR); + + PropertyValue value = property.getValue(); + + if (value.isString()) { + result.append(STRING_PREFIX).append(value.toString()).append(STRING_SUFFIX); + } else if (value.isNull()) { + result.append(NULL_STRING); + } else if (value.isDouble()) { + result.append(value.toString()).append(DOUBLE_SUFFIX); + } else if (value.isFloat()) { + result.append(value.toString()).append(FLOAT_SUFFIX); + } else if (value.isLong()) { + result.append(value.toString()).append(LONG_SUFFIX); + } else { + result.append(value.toString()); + } + + return result.toString(); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/GraphTransactionsToGDL.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/GraphTransactionsToGDL.java new file mode 100644 index 000000000000..a40654365e60 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/GraphTransactionsToGDL.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.io.impl.gdl.functions; + +import org.apache.flink.api.common.functions.GroupReduceFunction; +import org.apache.flink.util.Collector; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.flink.io.impl.gdl.GDLEncoder; +import org.gradoop.flink.model.impl.layouts.transactional.tuples.GraphTransaction; + +import java.util.ArrayList; +import java.util.List; + +/** + * A reduce group function that converts graph transactions to a GDL string. + */ +public class GraphTransactionsToGDL implements GroupReduceFunction { + + /** + * {@inheritDoc} + */ + @Override + public void reduce(Iterable graphTransactions, Collector out) + throws Exception { + List graphHeads = new ArrayList<>(); + List vertices = new ArrayList<>(); + List edges = new ArrayList<>(); + + for (GraphTransaction gt : graphTransactions) { + graphHeads.add(gt.getGraphHead()); + vertices.addAll(gt.getVertices()); + edges.addAll(gt.getEdges()); + } + + GDLEncoder encoder = new GDLEncoder(graphHeads, vertices, edges); + String result = encoder.getGDLString(); + + out.collect(result); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/package-info.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/package-info.java new file mode 100644 index 000000000000..319a0b96eece --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/functions/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains classes related to the conversion of data into the gdl format. + */ +package org.gradoop.flink.io.impl.gdl.functions; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/package-info.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/package-info.java new file mode 100644 index 000000000000..dc92697607fb --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/gdl/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains classes related to the output of data in the gdl format. + */ +package org.gradoop.flink.io.impl.gdl; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/TLFDataSource.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/TLFDataSource.java index 1451cafd91fe..419f49b024f0 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/TLFDataSource.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/TLFDataSource.java @@ -69,16 +69,18 @@ public TLFDataSource(String tlfPath, String tlfVertexDictionaryPath, super(tlfPath, tlfVertexDictionaryPath, tlfEdgeDictionaryPath, config); ExecutionEnvironment env = config.getExecutionEnvironment(); if (hasVertexDictionary()) { - DataSet> dictionary = env.createInput(HadoopInputs.readHadoopFile( + DataSet> dictionary = env.createInput(HadoopInputs.readHadoopFile( new TextInputFormat(), LongWritable.class, Text.class, getTLFVertexDictionaryPath())) - .map(new DictionaryEntry()) - .reduceGroup(new Dictionary()); + .filter(t -> !t.f1.toString().isEmpty()) + .map(new DictionaryEntry()) + .reduceGroup(new Dictionary()); setVertexDictionary(dictionary); } if (hasEdgeDictionary()) { DataSet> dictionary = env.createInput(HadoopInputs.readHadoopFile( - new TextInputFormat(), LongWritable.class, Text.class, getTLFEdgeDictionaryPath())) + new TextInputFormat(), LongWritable.class, Text.class, getTLFEdgeDictionaryPath())) + .filter(t -> !t.f1.toString().isEmpty()) .map(new DictionaryEntry()) .reduceGroup(new Dictionary()); @@ -107,10 +109,7 @@ public GraphCollection getGraphCollection() { // load tlf graphs from file assert input != null; - transactions = input.map(new GraphTransactionFromText( - getConfig().getGraphHeadFactory(), - getConfig().getVertexFactory(), - getConfig().getEdgeFactory())); + transactions = input.map(new GraphTransactionFromText(getConfig())); // map the integer valued labels to strings from dictionary if (hasVertexDictionary()) { diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/DictionaryEntry.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/DictionaryEntry.java index 4df02abff9fc..3bd2eaf0180f 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/DictionaryEntry.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/DictionaryEntry.java @@ -48,8 +48,7 @@ public DictionaryEntry() { * @throws Exception */ @Override - public Tuple2 map( - Tuple2 tuple) throws Exception { + public Tuple2 map(Tuple2 tuple) throws Exception { String[] stringArray = tuple.getField(1).toString().split(" "); returnTuple.f0 = Integer.parseInt(stringArray[1]); returnTuple.f1 = stringArray[0]; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/GraphTransactionFromText.java b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/GraphTransactionFromText.java index 7bcdfaa74d6c..2eaf8544c98e 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/GraphTransactionFromText.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/io/impl/tlf/functions/GraphTransactionFromText.java @@ -15,8 +15,6 @@ */ package org.gradoop.flink.io.impl.tlf.functions; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import org.apache.flink.api.common.functions.MapFunction; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.hadoop.io.LongWritable; @@ -30,9 +28,14 @@ import org.gradoop.common.model.impl.pojo.VertexFactory; import org.gradoop.flink.io.impl.tlf.TLFConstants; import org.gradoop.flink.model.impl.layouts.transactional.tuples.GraphTransaction; +import org.gradoop.flink.util.GradoopFlinkConfig; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Reads graph imported from a TLF file. The result of the mapping is a @@ -54,43 +57,16 @@ public class GraphTransactionFromText * Edge factory. */ private EdgeFactory edgeFactory; - /** - * Line fields splittet by space. - */ - private String[] fields; - /** - * String builder for each line. - */ - private StringBuilder stringBuilder = new StringBuilder(); - /** - * String builder for label with spaces. - */ - private StringBuilder labelBuilder = new StringBuilder(); - /** - * Map for long id from tlf file to gradoop id. - */ - private Map idMap = Maps.newHashMap(); - /** - * Vertices of transaction. - */ - private Set vertices = Sets.newHashSet(); - /** - * Edges of transaction. - */ - private Set edges = Sets.newHashSet(); /** * Valued constructor. * - * @param graphHeadFactory graph head factory - * @param vertexFactory vertex factory - * @param edgeFactory edge factory + * @param config gradoop flink config */ - public GraphTransactionFromText(GraphHeadFactory graphHeadFactory, VertexFactory vertexFactory, - EdgeFactory edgeFactory) { - this.graphHeadFactory = graphHeadFactory; - this.vertexFactory = vertexFactory; - this.edgeFactory = edgeFactory; + public GraphTransactionFromText(GradoopFlinkConfig config) { + this.graphHeadFactory = config.getGraphHeadFactory(); + this.vertexFactory = config.getVertexFactory(); + this.edgeFactory = config.getEdgeFactory(); } /** @@ -98,61 +74,40 @@ public GraphTransactionFromText(GraphHeadFactory graphHeadFactory, VertexFactory * * @param inputTuple consists of a key(LongWritable) and a value(Text) * @return a TLFGraph created by the input text - * @throws Exception + * @throws Exception on failure */ @Override public GraphTransaction map(Tuple2 inputTuple) throws Exception { - idMap.clear(); - vertices.clear(); - edges.clear(); - stringBuilder.setLength(0); - boolean firstLine = true; - boolean vertexLine = true; - String graph = inputTuple.f1.toString(); - int cursor = 0; - char currChar; - - GradoopId gradoopId; + Map idMap = new HashMap<>(); + Set vertices = new HashSet<>(); + Set edges = new HashSet<>(); GraphHead graphHead = null; - Vertex vertex; - Edge edge; - do { - currChar = graph.charAt(cursor); - if (currChar == '\n') { - fields = stringBuilder.toString().trim().split(" "); - if (firstLine) { - gradoopId = GradoopId.get(); - idMap.put(Long.valueOf(fields[2]), gradoopId); - graphHead = graphHeadFactory.initGraphHead(gradoopId); - firstLine = false; - } else { - if (vertexLine) { - gradoopId = GradoopId.get(); - idMap.put(Long.valueOf(fields[1]), gradoopId); - vertex = vertexFactory.initVertex(gradoopId, getLabel(2)); - vertex.addGraphId(graphHead.getId()); - vertices.add(vertex); - if (TLFConstants.EDGE_SYMBOL.equals(String.valueOf(graph.charAt(cursor + 1)))) { - vertexLine = false; - } - } else { - gradoopId = GradoopId.get(); - edge = edgeFactory.initEdge(gradoopId, - getLabel(3), - idMap.get(Long.valueOf(fields[1])), - idMap.get(Long.valueOf(fields[2])) - ); - edge.addGraphId(graphHead.getId()); - edges.add(edge); - } - } - stringBuilder.setLength(0); - } else { - stringBuilder.append(currChar); + String[] lines = inputTuple.f1.toString().split("\\R", -1); + for (int i = 0; i < lines.length; i++) { + String[] fields = lines[i].trim().split(" "); + GradoopId gradoopId = GradoopId.get(); + + if (i == 0) { + idMap.put(Long.valueOf(fields[2]), gradoopId); + graphHead = graphHeadFactory.initGraphHead(gradoopId); + + } else if (TLFConstants.VERTEX_SYMBOL.equals(fields[0])) { + idMap.put(Long.valueOf(fields[1]), gradoopId); + Vertex vertex = vertexFactory.initVertex(gradoopId, getLabel(fields, 2)); + vertex.addGraphId(graphHead.getId()); + vertices.add(vertex); + + } else if (TLFConstants.EDGE_SYMBOL.equals(fields[0])) { + Edge edge = edgeFactory.initEdge(gradoopId, + getLabel(fields, 3), + idMap.get(Long.valueOf(fields[1])), + idMap.get(Long.valueOf(fields[2])) + ); + edge.addGraphId(graphHead.getId()); + edges.add(edge); } - cursor++; - } while (cursor != graph.length()); + } return new GraphTransaction(graphHead, vertices, edges); } @@ -161,17 +116,11 @@ public GraphTransaction map(Tuple2 inputTuple) throws Except * Builds a label from the current fields. If the label is split by whitespaces the last fields * which represent the label will be concatenated. * + * @param fields graph element fields * @param labelStart field where the label starts * @return full label */ - private String getLabel(int labelStart) { - labelBuilder.setLength(0); - for (int i = labelStart; i < fields.length; i++) { - if (i > labelStart) { - labelBuilder.append(" "); - } - labelBuilder.append(fields[i]); - } - return labelBuilder.toString(); + private String getLabel(String[] fields, int labelStart) { + return Arrays.stream(fields).skip(labelStart).collect(Collectors.joining(" ")); } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/GraphCollection.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/GraphCollection.java index 707da97a4fe4..3b70c905b7ce 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/GraphCollection.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/GraphCollection.java @@ -25,6 +25,7 @@ import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.common.util.Order; import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.impl.gdl.GDLConsoleOutput; import org.gradoop.flink.model.api.functions.GraphHeadReduceFunction; import org.gradoop.flink.model.api.layouts.GraphCollectionLayout; import org.gradoop.flink.model.api.operators.ApplicableUnaryGraphToGraphOperator; @@ -461,4 +462,13 @@ public GraphCollection groupByIsomorphism(GraphHeadReduceFunction func) { public void writeTo(DataSink dataSink) throws IOException { dataSink.write(this); } + + /** + * Prints this graph collection to the console. + * + * @throws Exception forwarded DataSet print() Exception. + */ + public void print() throws Exception { + GDLConsoleOutput.print(this); + } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraph.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraph.java index c14a24d04664..28392b6d5dcf 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraph.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraph.java @@ -23,6 +23,7 @@ import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.io.impl.gdl.GDLConsoleOutput; import org.gradoop.flink.model.api.functions.AggregateFunction; import org.gradoop.flink.model.api.functions.EdgeAggregateFunction; import org.gradoop.flink.model.api.functions.TransformationFunction; @@ -53,7 +54,7 @@ import org.gradoop.flink.model.impl.operators.neighborhood.ReduceEdgeNeighborhood; import org.gradoop.flink.model.impl.operators.neighborhood.ReduceVertexNeighborhood; import org.gradoop.flink.model.impl.operators.overlap.Overlap; -import org.gradoop.flink.model.impl.operators.sampling.RandomVertexSampling; +import org.gradoop.flink.model.impl.operators.sampling.SamplingAlgorithm; import org.gradoop.flink.model.impl.operators.split.Split; import org.gradoop.flink.model.impl.operators.subgraph.Subgraph; import org.gradoop.flink.model.impl.operators.tostring.functions.EdgeToDataString; @@ -366,8 +367,8 @@ public LogicalGraph aggregate(AggregateFunction aggregateFunc) { * {@inheritDoc} */ @Override - public LogicalGraph sampleRandomNodes(float sampleSize) { - return callForGraph(new RandomVertexSampling(sampleSize)); + public LogicalGraph sample(SamplingAlgorithm algorithm) { + return callForGraph(algorithm); } /** @@ -437,24 +438,24 @@ public LogicalGraph reduceOnNeighbors( * {@inheritDoc} */ @Override - public LogicalGraph drillUpVertex(String propertyKey, DrillFunction function) { - return drillUpVertex(null, propertyKey, function); + public LogicalGraph rollUpVertex(String propertyKey, DrillFunction function) { + return rollUpVertex(null, propertyKey, function); } /** * {@inheritDoc} */ @Override - public LogicalGraph drillUpVertex( + public LogicalGraph rollUpVertex( String vertexLabel, String propertyKey, DrillFunction function) { - return drillUpVertex(vertexLabel, propertyKey, function, null); + return rollUpVertex(vertexLabel, propertyKey, function, null); } /** * {@inheritDoc} */ @Override - public LogicalGraph drillUpVertex( + public LogicalGraph rollUpVertex( String vertexLabel, String propertyKey, DrillFunction function, String newPropertyKey) { Objects.requireNonNull(propertyKey, "missing property key"); @@ -463,8 +464,7 @@ public LogicalGraph drillUpVertex( Drill.DrillBuilder builder = new Drill.DrillBuilder(); builder.setPropertyKey(propertyKey); - builder.setFunction(function); - builder.drillVertex(true); + builder.setVertexDrillFunction(function); if (vertexLabel != null) { builder.setLabel(vertexLabel); @@ -473,30 +473,30 @@ public LogicalGraph drillUpVertex( builder.setNewPropertyKey(newPropertyKey); } - return callForGraph(builder.buildDrillUp()); + return callForGraph(builder.buildRollUp()); } /** * {@inheritDoc} */ @Override - public LogicalGraph drillUpEdge(String propertyKey, DrillFunction function) { - return drillUpEdge(null, propertyKey, function); + public LogicalGraph rollUpEdge(String propertyKey, DrillFunction function) { + return rollUpEdge(null, propertyKey, function); } /** * {@inheritDoc} */ @Override - public LogicalGraph drillUpEdge(String edgeLabel, String propertyKey, DrillFunction function) { - return drillUpEdge(edgeLabel, propertyKey, function, null); + public LogicalGraph rollUpEdge(String edgeLabel, String propertyKey, DrillFunction function) { + return rollUpEdge(edgeLabel, propertyKey, function, null); } /** * {@inheritDoc} */ @Override - public LogicalGraph drillUpEdge( + public LogicalGraph rollUpEdge( String edgeLabel, String propertyKey, DrillFunction function, String newPropertyKey) { Objects.requireNonNull(propertyKey, "missing property key"); @@ -505,8 +505,7 @@ public LogicalGraph drillUpEdge( Drill.DrillBuilder builder = new Drill.DrillBuilder(); builder.setPropertyKey(propertyKey); - builder.setFunction(function); - builder.drillEdge(true); + builder.setEdgeDrillFunction(function); if (edgeLabel != null) { builder.setLabel(edgeLabel); @@ -515,7 +514,7 @@ public LogicalGraph drillUpEdge( builder.setNewPropertyKey(newPropertyKey); } - return callForGraph(builder.buildDrillUp()); + return callForGraph(builder.buildRollUp()); } /** @@ -563,8 +562,7 @@ public LogicalGraph drillDownVertex( Drill.DrillBuilder builder = new Drill.DrillBuilder(); builder.setPropertyKey(propertyKey); - builder.setFunction(function); - builder.drillVertex(true); + builder.setVertexDrillFunction(function); if (vertexLabel != null) { builder.setLabel(vertexLabel); @@ -573,7 +571,7 @@ public LogicalGraph drillDownVertex( builder.setNewPropertyKey(newPropertyKey); } if (function != null) { - builder.setFunction(function); + builder.setVertexDrillFunction(function); } return callForGraph(builder.buildDrillDown()); @@ -624,8 +622,7 @@ public LogicalGraph drillDownEdge( Drill.DrillBuilder builder = new Drill.DrillBuilder(); builder.setPropertyKey(propertyKey); - builder.setFunction(function); - builder.drillEdge(true); + builder.setEdgeDrillFunction(function); if (edgeLabel != null) { builder.setLabel(edgeLabel); @@ -634,7 +631,7 @@ public LogicalGraph drillDownEdge( builder.setNewPropertyKey(newPropertyKey); } if (function != null) { - builder.setFunction(function); + builder.setEdgeDrillFunction(function); } return callForGraph(builder.buildDrillDown()); @@ -770,4 +767,13 @@ public DataSet isEmpty() { public void writeTo(DataSink dataSink) throws IOException { dataSink.write(this); } + + /** + * Prints the GDL formatted graph to the standard output. + * + * @throws Exception forwarded from dataset print + */ + public void print() throws Exception { + GDLConsoleOutput.print(this); + } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraphOperators.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraphOperators.java index 4d4e14223bec..5f50617637a5 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraphOperators.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/api/epgm/LogicalGraphOperators.java @@ -35,6 +35,7 @@ import org.gradoop.flink.model.impl.operators.matching.common.MatchStrategy; import org.gradoop.flink.model.impl.operators.matching.common.statistics.GraphStatistics; import org.gradoop.flink.model.impl.operators.neighborhood.Neighborhood; +import org.gradoop.flink.model.impl.operators.sampling.SamplingAlgorithm; import org.gradoop.flink.model.impl.operators.subgraph.Subgraph; import java.util.List; @@ -401,10 +402,10 @@ LogicalGraph subgraph(FilterFunction vertexFilterFunction, * Creates a new graph from a randomly chosen subset of nodes and their * associated edges. * - * @param sampleSize relative amount of nodes in the result graph + * @param algorithm used sampling algorithm * @return logical graph with random nodes and their associated edges */ - LogicalGraph sampleRandomNodes(float sampleSize); + LogicalGraph sample(SamplingAlgorithm algorithm); /** * Creates a condensed version of the logical graph by grouping vertices based on the specified @@ -527,7 +528,7 @@ LogicalGraph reduceOnNeighbors( DataSet equalsByData(LogicalGraph other); /** - * Applies a given drill-up (transformation) function on a single vertex property of the input + * Applies a given roll-up (transformation) function on a single vertex property of the input * graph. The property is identified by the specified property key. The previous version of the * property value is stored at the vertex. The structure of the graph remains unchanged. * @@ -537,12 +538,12 @@ LogicalGraph reduceOnNeighbors( * * @param propertyKey property key * @param function drill up function - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpVertex(String propertyKey, DrillFunction function); + LogicalGraph rollUpVertex(String propertyKey, DrillFunction function); /** - * Applies a given drill-up (transformation) function on a single vertex property of the input + * Applies a given roll-up (transformation) function on a single vertex property of the input * graph. The vertices are selected by their label and the property is identified by the * specified property key. The previous version of the property value is stored at the vertex. * The structure of the graph remains unchanged. @@ -554,12 +555,12 @@ LogicalGraph reduceOnNeighbors( * @param vertexLabel vertex label * @param propertyKey property key * @param function drill up function - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpVertex(String vertexLabel, String propertyKey, DrillFunction function); + LogicalGraph rollUpVertex(String vertexLabel, String propertyKey, DrillFunction function); /** - * Applies a given drill-up (transformation) function on a single vertex property of the input + * Applies a given roll-up (transformation) function on a single vertex property of the input * graph. The vertices are selected by their label and the property is identified by the * specified property key. The new version of the property value is stored at the vertex * under the new property key. The structure of the graph remains unchanged. @@ -572,13 +573,13 @@ LogicalGraph reduceOnNeighbors( * @param propertyKey property key * @param function drill up function * @param newPropertyKey new property key - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpVertex( + LogicalGraph rollUpVertex( String vertexLabel, String propertyKey, DrillFunction function, String newPropertyKey); /** - * Applies a given drill-up (transformation) function on a single edge property of the input + * Applies a given roll-up (transformation) function on a single edge property of the input * graph. The property is identified by the specified property key. The previous version of the * property value is stored at the edge. The structure of the graph remains unchanged. * @@ -588,12 +589,12 @@ LogicalGraph drillUpVertex( * * @param propertyKey property key * @param function drill up function - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpEdge(String propertyKey, DrillFunction function); + LogicalGraph rollUpEdge(String propertyKey, DrillFunction function); /** - * Applies a given drill-up (transformation) function on a single edge property of the input + * Applies a given roll-up (transformation) function on a single edge property of the input * graph. The edges are selected by their label and the property is identified by the * specified property key. The previous version of the property value is stored at the edge. * The structure of the graph remains unchanged. @@ -605,12 +606,12 @@ LogicalGraph drillUpVertex( * @param edgeLabel edge label * @param propertyKey property key * @param function drill up function - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpEdge(String edgeLabel, String propertyKey, DrillFunction function); + LogicalGraph rollUpEdge(String edgeLabel, String propertyKey, DrillFunction function); /** - * Applies a given drill-up (transformation) function on a single edge property of the input + * Applies a given roll-up (transformation) function on a single edge property of the input * graph. The edges are selected by their label and the property is identified by the * specified property key. The new version of the property value is stored at the edge * under the new property key. The structure of the graph remains unchanged. @@ -623,15 +624,15 @@ LogicalGraph drillUpVertex( * @param propertyKey property key * @param function drill up function * @param newPropertyKey new property key - * @return graph with drilled up properties + * @return graph with rolled up properties */ - LogicalGraph drillUpEdge( + LogicalGraph rollUpEdge( String edgeLabel, String propertyKey, DrillFunction function, String newPropertyKey); /** * Applies a drill-down operation on a single vertex property of the input graph. The property * is identified by the specified property key. The detailed version of the property value has - * to be stored at the vertex as a result from a previous drill-up operation. + * to be stored at the vertex as a result from a previous roll-up operation. * * This is a convenience function for * {@link LogicalGraph#transformVertices(TransformationFunction)} and can be used as a @@ -646,7 +647,7 @@ LogicalGraph drillUpEdge( * Applies a given drill-down operation on a single vertex property of the input graph. The * vertices are selected by their label and the property is identified by the specified * property key. The detailed version of the property value has to be stored at the vertex as a - * result from a previous drill-up operation. The structure of the graph remains unchanged. + * result from a previous roll-up operation. The structure of the graph remains unchanged. * * This is a convenience function for * {@link LogicalGraph#transformVertices(TransformationFunction)} and can be used as a @@ -713,7 +714,7 @@ LogicalGraph drillDownVertex( /** * Applies a drill-down operation on a single edge property of the input graph. The property * is identified by the specified property key. The detailed version of the property value has - * to be stored at the edge as a result from a previous drill-up operation. + * to be stored at the edge as a result from a previous roll-up operation. * * This is a convenience function for * {@link LogicalGraph#transformVertices(TransformationFunction)} and can be used as a @@ -728,7 +729,7 @@ LogicalGraph drillDownVertex( * Applies a given drill-down operation on a single edge property of the input graph. The * edges are selected by their label and the property is identified by the specified * property key. The detailed version of the property value has to be stored at the edge as a - * result from a previous drill-up operation. The structure of the graph remains unchanged. + * result from a previous roll-up operation. The structure of the graph remains unchanged. * * This is a convenience function for * {@link LogicalGraph#transformVertices(TransformationFunction)} and can be used as a diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project3To0.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project3To0.java index 97bff7c2236c..6d53cc7caea3 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project3To0.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project3To0.java @@ -27,7 +27,6 @@ * @param f1 type * @param f2 type */ -@FunctionAnnotation.ReadFields("f0") @FunctionAnnotation.ForwardedFields("f0") public class Project3To0 implements MapFunction, Tuple1> { diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project4To0And1.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project4To0And1.java index ed125e58b3b2..1a852303229d 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project4To0And1.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Project4To0And1.java @@ -28,8 +28,7 @@ * @param f2 type * @param f3 type */ -@FunctionAnnotation.ReadFields("f0;f1") -@FunctionAnnotation.ForwardedFields("f0->f0;f1->f1") +@FunctionAnnotation.ForwardedFields("f0;f1") public class Project4To0And1 implements MapFunction, Tuple2> { diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/SwitchPair.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/SwitchPair.java index defc1cf0bd0c..ea145ff9f831 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/SwitchPair.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/SwitchPair.java @@ -28,8 +28,15 @@ public class SwitchPair implements MapFunction, Tuple2> { + /** + * Reduce object instantiations. + */ + private final Tuple2 reuse = new Tuple2<>(); + @Override public Tuple2 map(Tuple2 pair) throws Exception { - return new Tuple2<>(pair.f1, pair.f0); + reuse.f0 = pair.f1; + reuse.f1 = pair.f0; + return reuse; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Value2Of3.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Value2Of3.java index 3467346c007b..b8d0e058ad83 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Value2Of3.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/Value2Of3.java @@ -16,6 +16,7 @@ package org.gradoop.flink.model.impl.functions.tuple; import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.FunctionAnnotation; import org.apache.flink.api.java.functions.KeySelector; import org.apache.flink.api.java.tuple.Tuple3; @@ -26,6 +27,7 @@ * @param f1 type * @param f2 type */ +@FunctionAnnotation.ForwardedFields("f2->*") public class Value2Of3 implements MapFunction, T2>, KeySelector, T2> { diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueInTuple1.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueInTuple1.java index c14c7ec01178..0f79d02bb440 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueInTuple1.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueInTuple1.java @@ -20,8 +20,11 @@ /** * Wraps a value in a tuple 1. + * * @param value type + * @deprecated This function is a duplicate of {@link ObjectTo1}, use it instead. */ +@Deprecated public class ValueInTuple1 implements MapFunction> { @Override diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueOfWithCount.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueOfWithCount.java index 38d0e22ca83e..f6de3d9177c1 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueOfWithCount.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/functions/tuple/ValueOfWithCount.java @@ -20,7 +20,7 @@ /** * (object, count) => object - * @param + * @param value type */ public class ValueOfWithCount implements MapFunction, T> { diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasEdgeLabel.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasEdgeLabel.java index 80efcf82a47a..626bebb84458 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasEdgeLabel.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasEdgeLabel.java @@ -26,6 +26,11 @@ */ public class HasEdgeLabel extends HasLabel implements EdgeAggregateFunction { + /** + * Prefix of the property key generated by {@link HasEdgeLabel} aggregate function. + */ + private static final String PROPERTY_KEY_PREFIX_HAS_EDGE_LABEL = "hasEdgeLabel_"; + /** * Constructor. * @@ -42,6 +47,6 @@ public PropertyValue getEdgeIncrement(Edge edge) { @Override public String getAggregatePropertyKey() { - return "hasEdgeLabel_" + label; + return PROPERTY_KEY_PREFIX_HAS_EDGE_LABEL + label; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasVertexLabel.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasVertexLabel.java index 738244345aa2..9c5286e25699 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasVertexLabel.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/containment/HasVertexLabel.java @@ -27,6 +27,11 @@ public class HasVertexLabel extends HasLabel implements VertexAggregateFunction { + /** + * Prefix of the property key generated by {@link HasVertexLabel} aggregate function. + */ + private static final String PROPERTY_KEY_PREFIX_HAS_VERTEX_LABEL = "hasVertexLabel_"; + /** * Constructor. * @@ -43,7 +48,7 @@ public PropertyValue getVertexIncrement(Vertex vertex) { @Override public String getAggregatePropertyKey() { - return "hasVertexLabel_" + label; + return PROPERTY_KEY_PREFIX_HAS_VERTEX_LABEL + label; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/EdgeCount.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/EdgeCount.java index 2679b18022cd..1ff035c8c823 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/EdgeCount.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/EdgeCount.java @@ -24,6 +24,11 @@ */ public class EdgeCount extends Count implements EdgeAggregateFunction { + /** + * Key of the property generated by {@link EdgeCount} aggregate function. + */ + private static final String PROPERTY_KEY_EDGE_COUNT = "edgeCount"; + @Override public PropertyValue getEdgeIncrement(Edge edge) { return PropertyValue.create(1L); @@ -31,6 +36,6 @@ public PropertyValue getEdgeIncrement(Edge edge) { @Override public String getAggregatePropertyKey() { - return "edgeCount"; + return PROPERTY_KEY_EDGE_COUNT; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/VertexCount.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/VertexCount.java index c156c0beaa2e..c5b301ae1bf4 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/VertexCount.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/count/VertexCount.java @@ -24,6 +24,11 @@ */ public class VertexCount extends Count implements VertexAggregateFunction { + /** + * Key of the property generated by {@link VertexCount} aggregate function. + */ + private static final String PROPERTY_KEY_VERTEX_COUNT = "vertexCount"; + @Override public PropertyValue getVertexIncrement(Vertex vertex) { return PropertyValue.create(1L); @@ -31,6 +36,6 @@ public PropertyValue getVertexIncrement(Vertex vertex) { @Override public String getAggregatePropertyKey() { - return "vertexCount"; + return PROPERTY_KEY_VERTEX_COUNT; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/max/MaxProperty.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/max/MaxProperty.java index b234db902852..7904b9785424 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/max/MaxProperty.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/max/MaxProperty.java @@ -19,6 +19,12 @@ * Superclass of aggregate functions that determine a maximal property value. */ public abstract class MaxProperty extends Max { + + /** + * Prefix of the property key generated by {@link MaxProperty} aggregate function. + */ + private static final String PROPERTY_KEY_PREFIX_MAX = "max_"; + /** * Property key whose value should be aggregated. */ @@ -35,6 +41,6 @@ public MaxProperty(String propertyKey) { @Override public String getAggregatePropertyKey() { - return "max_" + propertyKey; + return PROPERTY_KEY_PREFIX_MAX + propertyKey; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/min/MinProperty.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/min/MinProperty.java index c254f93134a4..12a706b5f1fd 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/min/MinProperty.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/min/MinProperty.java @@ -19,6 +19,12 @@ * Superclass of aggregate functions that determine a minimal property value. */ public abstract class MinProperty extends Min { + + /** + * Prefix of the property key generated by {@link MinProperty} aggregate function. + */ + private static final String PROPERTY_KEY_PREFIX_MIN = "min_"; + /** * Property key whose value should be aggregated. */ @@ -35,6 +41,6 @@ public MinProperty(String propertyKey) { @Override public String getAggregatePropertyKey() { - return "min_" + propertyKey; + return PROPERTY_KEY_PREFIX_MIN + propertyKey; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/sum/SumProperty.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/sum/SumProperty.java index 505b8af37675..7931a8a08917 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/sum/SumProperty.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/aggregation/functions/sum/SumProperty.java @@ -23,6 +23,11 @@ */ public abstract class SumProperty extends Sum implements AggregateFunction { + /** + * Prefix of the property key generated by {@link SumProperty} aggregate function. + */ + private static final String PROPERTY_KEY_PREFIX_SUM = "sum_"; + /** * Property key whose value should be aggregated. */ @@ -39,6 +44,6 @@ public SumProperty(String propertyKey) { @Override public String getAggregatePropertyKey() { - return "sum_" + propertyKey; + return PROPERTY_KEY_PREFIX_SUM + propertyKey; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/Drill.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/Drill.java index fafa5812f989..164435bee8a1 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/Drill.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/Drill.java @@ -28,6 +28,27 @@ */ public abstract class Drill implements UnaryGraphToGraphOperator { + /** + * Supported elements. + */ + public enum Element { + /** + * Vertices + */ + VERTICES, + /** + * Edges + */ + EDGES, + /** + * Graph head + */ + GRAPHHEAD + } + /** + * Element to be covered by the operation. + */ + private Element element; /** * Label of the element whose property shall be drilled. */ @@ -37,33 +58,48 @@ public abstract class Drill implements UnaryGraphToGraphOperator { */ private String propertyKey; /** - * Drill function which shall be applied to a property. + * Drill function which shall be applied to a property of a vertex. */ - private DrillFunction function; + private DrillFunction vertexDrillFunction; /** - * New property key. + * Drill function which shall be applied to a property of an edge. */ - private String newPropertyKey; + private DrillFunction edgeDrillFunction; + /** + * Drill function which shall be applied to a property of a graph head. + */ + private DrillFunction graphheadDrillFunction; /** - * True, if vertices shall be drilled, false for edges + * New property key. */ - private boolean drillVertex; + private String newPropertyKey; /** * Valued constructor. - * @param label label of the element whose property shall be drilled + * + * @param label label of the element whose property shall be drilled * @param propertyKey property key - * @param function drill function which shall be applied to a property + * @param vertexDrillFunction drill function which shall be applied to a property of a vertex + * @param edgeDrillFunction drill function which shall be applied to a property of an edge + * @param graphheadDrillFunction drill function which shall be applied to a property of a + * graph head * @param newPropertyKey new property key - * @param drillVertex true, if vertices shall be drilled, false for edges + * @param element Element to be covered by the operation */ - Drill(String label, String propertyKey, DrillFunction function, String newPropertyKey, - boolean drillVertex) { + Drill(String label, String propertyKey, DrillFunction vertexDrillFunction, + DrillFunction edgeDrillFunction, DrillFunction graphheadDrillFunction, + String newPropertyKey, Element element) { + this.element = element != null ? element : Element.VERTICES; this.label = label; this.propertyKey = propertyKey; - this.function = function; + this.vertexDrillFunction = vertexDrillFunction; + this.edgeDrillFunction = edgeDrillFunction; + this.graphheadDrillFunction = graphheadDrillFunction; this.newPropertyKey = newPropertyKey; - this.drillVertex = drillVertex; + } + + protected Element getElement() { + return element; } protected String getLabel() { @@ -74,21 +110,20 @@ protected String getPropertyKey() { return propertyKey; } - protected DrillFunction getFunction() { - return function; + protected DrillFunction getVertexDrillFunction() { + return vertexDrillFunction; } - protected String getNewPropertyKey() { - return newPropertyKey; + protected DrillFunction getEdgeDrillFunction() { + return edgeDrillFunction; } - /** - * True, if vertices shall be drilled, false for edges - * - * @return true for vertex drilling - */ - protected boolean drillVertex() { - return drillVertex; + protected DrillFunction getGraphheadDrillFunction() { + return graphheadDrillFunction; + } + + protected String getNewPropertyKey() { + return newPropertyKey; } /** @@ -113,6 +148,10 @@ protected boolean keepCurrentPropertyKey() { * Used for building a drill operator instance. */ public static class DrillBuilder { + /** + * Element to be covered by the operation. + */ + private Element element; /** * Label of the element whose property shall be drilled. */ @@ -122,28 +161,43 @@ public static class DrillBuilder { */ private String propertyKey; /** - * Drill function which shall be applied to a property. + * Drill function which shall be applied to a property of a vertex. */ - private DrillFunction function; + private DrillFunction vertexDrillFunction; /** - * New property key. + * Drill function which shall be applied to a property of an edge. */ - private String newPropertyKey; + private DrillFunction edgeDrillFunction; + /** + * Drill function which shall be applied to a property of a graph head. + */ + private DrillFunction graphheadDrillFunction; /** - * True, if vertices shall be drilled, false for edges + * New property key. */ - private boolean drillVertex; + private String newPropertyKey; /** - * Creates the drill up / drill down class. By default the vertices will be transformed, note - * that {@link DrillBuilder#drillVertex{boolean} and - * {@link DrillBuilder#drillEdge(boolean)} negate each other so only the last used will be - * considered. In case of drill down where the function is not set it is necessary that a + * Creates the drill up / drill down class. Note that only one DrillFunction must be set. + * In case of drill down where the function is not set it is necessary that a * drill up function was used before. */ public DrillBuilder() { - function = null; - drillVertex = true; + vertexDrillFunction = null; + edgeDrillFunction = null; + graphheadDrillFunction = null; + element = null; + } + + /** + * Specifies the element to be covered by the operation. + * + * @param element element to be covered by the operation + * @return the modified drill builder + */ + public DrillBuilder setElement(Element element) { + this.element = element; + return this; } /** @@ -171,57 +225,88 @@ public DrillBuilder setPropertyKey(String propertyKey) { /** * Specifies the function to calculate the new value. * - * @param function drill function + *

+ * Note: Only one DrillFunction must be set and thus this function unset's all other + * possibly set DrillFunction's. + *

+ * + * @param vertexDrillFunction the drill function for vertices * @return the modified drill builder */ - public DrillBuilder setFunction(DrillFunction function) { - this.function = function; + public DrillBuilder setVertexDrillFunction(DrillFunction vertexDrillFunction) { + this.vertexDrillFunction = vertexDrillFunction; + this.edgeDrillFunction = null; + this.graphheadDrillFunction = null; + this.element = Element.VERTICES; return this; } /** - * Specifies the new key of the drilled value. + * Specifies the function to calculate the new value. * - * @param newPropertyKey new property key + *

+ * Note: Only one DrillFunction must be set and thus this function unset's all other + * possibly set DrillFunction's. + *

+ * + * @param edgeDrillFunction the drill function for edges * @return the modified drill builder */ - public DrillBuilder setNewPropertyKey(String newPropertyKey) { - this.newPropertyKey = newPropertyKey; + public DrillBuilder setEdgeDrillFunction(DrillFunction edgeDrillFunction) { + this.edgeDrillFunction = edgeDrillFunction; + this.vertexDrillFunction = null; + this.graphheadDrillFunction = null; + this.element = Element.EDGES; return this; } /** - * Specifies if a vertex shall be drilled. Negates edge drilling. + * Specifies the function to calculate the new value. * - * @param drillVertex true to enable vertex drilling + *

+ * Note: Only one DrillFunction must be set and thus this function unset's all other + * possibly set DrillFunction's. + *

+ * + * @param graphheadDrillFunction the drill function for graph heads * @return the modified drill builder */ - public DrillBuilder drillVertex(boolean drillVertex) { - this.drillVertex = drillVertex; + public DrillBuilder setGraphheadDrillFunction(DrillFunction graphheadDrillFunction) { + this.graphheadDrillFunction = graphheadDrillFunction; + this.vertexDrillFunction = null; + this.edgeDrillFunction = null; + this.element = Element.GRAPHHEAD; return this; } /** - * Specifies if an edge shall be drilled. Negates vertex drilling. + * Specifies the new key of the drilled value. * - * @param drillEdge true to enable edge drilling + * @param newPropertyKey new property key * @return the modified drill builder */ - public DrillBuilder drillEdge(boolean drillEdge) { - this.drillVertex = !drillEdge; + public DrillBuilder setNewPropertyKey(String newPropertyKey) { + this.newPropertyKey = newPropertyKey; return this; } /** - * Creates a drill up operation. + * Creates a roll up operation. * - * @return drill up operation + * @return roll up operation */ - public DrillUp buildDrillUp() { + public RollUp buildRollUp() { Objects.requireNonNull(propertyKey); - Objects.requireNonNull(function); - return new DrillUp( - label, propertyKey, function, newPropertyKey, drillVertex); + + if (vertexDrillFunction == null && + edgeDrillFunction == null && + graphheadDrillFunction == null) { + throw new IllegalArgumentException(); + } + + return new RollUp( + label, propertyKey, vertexDrillFunction, edgeDrillFunction, graphheadDrillFunction, + newPropertyKey, element); } /** @@ -232,7 +317,8 @@ public DrillUp buildDrillUp() { public DrillDown buildDrillDown() { Objects.requireNonNull(propertyKey); return new DrillDown( - label, propertyKey, function, newPropertyKey, drillVertex); + label, propertyKey, vertexDrillFunction, edgeDrillFunction, graphheadDrillFunction, + newPropertyKey, element); } } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillDown.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillDown.java index 4124cfeba6aa..c397e3eb0aef 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillDown.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillDown.java @@ -15,16 +15,14 @@ */ package org.gradoop.flink.model.impl.operators.drilling; -import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.operators.drilling.functions.drillfunctions.DrillFunction; import org.gradoop.flink.model.impl.operators.drilling.functions.transformations.DrillDownTransformation; /** * Creates a graph with the same structure but a specified property of an element is drilled down - * by the declared function. It is possible to drill down either on one vertex / edge type or all - * vertex / edge types. Additionally the drilled down value can be stored under a new key. If the + * by the declared function. The drilled down value can be stored under a new key. If the * original key shall be reused the old value is overwritten. Drill down can also be used * without specifying a drill down function when it is preceded by a roll up operation on the * same property key. @@ -34,29 +32,59 @@ public class DrillDown extends Drill { /** * Valued constructor. * - * @param label label of the element whose property shall be drilled - * @param propertyKey property key - * @param function drill function which shall be applied to a property - * @param newPropertyKey new property key - * @param drillVertex true, if vertices shall be drilled, false for edges + * @param label label of the element whose property shall be drilled + * @param propertyKey property key + * @param vertexDrillFunction drill function which shall be applied to a property of a vertex + * @param edgeDrillFunction drill function which shall be applied to a property of an edge + * @param graphheadDrillFunction drill function which shall be applied to a property of a + * graph head + * @param newPropertyKey new property key + * @param element Element to be covered by the operation */ public DrillDown( - String label, String propertyKey, DrillFunction function, String newPropertyKey, - boolean drillVertex) { - super(label, propertyKey, function, newPropertyKey, drillVertex); + String label, String propertyKey, DrillFunction vertexDrillFunction, + DrillFunction edgeDrillFunction, DrillFunction graphheadDrillFunction, + String newPropertyKey, Element element) { + super(label, propertyKey, vertexDrillFunction, edgeDrillFunction, + graphheadDrillFunction, newPropertyKey, element); } @Override public LogicalGraph execute(LogicalGraph graph) { - if (drillVertex()) { + switch (getElement()) { + case VERTICES: graph = graph.transformVertices( - new DrillDownTransformation(getLabel(), getPropertyKey(), getFunction(), - getNewPropertyKey(), drillAllLabels(), keepCurrentPropertyKey())); - } else { + new DrillDownTransformation<>( + getLabel(), + getPropertyKey(), + getVertexDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + case EDGES: graph = graph.transformEdges( - new DrillDownTransformation(getLabel(), getPropertyKey(), getFunction(), - getNewPropertyKey(), drillAllLabels(), keepCurrentPropertyKey())); + new DrillDownTransformation<>( + getLabel(), + getPropertyKey(), + getEdgeDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + case GRAPHHEAD: + graph = graph.transformGraphHead( + new DrillDownTransformation<>( + getLabel(), + getPropertyKey(), + getGraphheadDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + default: + throw new UnsupportedTypeException("Element type must be vertex, edge or graphhead"); } return graph; } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillUp.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/RollUp.java similarity index 50% rename from gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillUp.java rename to gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/RollUp.java index acac43b9c58c..98d7f9a6f76e 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/DrillUp.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/RollUp.java @@ -15,16 +15,14 @@ */ package org.gradoop.flink.model.impl.operators.drilling; -import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.operators.drilling.functions.drillfunctions.DrillFunction; -import org.gradoop.flink.model.impl.operators.drilling.functions.transformations.DrillUpTransformation; +import org.gradoop.flink.model.impl.operators.drilling.functions.transformations.RollUpTransformation; /** * Creates a graph with the same structure but a specified property of an element is drilled up - * by the declared function. It is possible to drill up either on one vertex / edge type or all - * vertex / edge types. Additionally the drilled up value can be stored under a new key. If the + * by the declared function. The drilled up value can be stored under a new key. If the * original key shall be reused the old value is stored under the key 'key__x' where 'x' is a * version number. This number increases on every continuous drill up call where the highest * number is the level direct below the drilled up one. @@ -46,38 +44,68 @@ * This example shows that this operation may be used as pre processing for the * {@link org.gradoop.flink.model.impl.operators.grouping.Grouping} operator. */ -public class DrillUp extends Drill { +public class RollUp extends Drill { /** * Valued constructor. * - * @param label label of the element whose property shall be drilled - * @param propertyKey property key - * @param function drill function which shall be applied to a property - * @param newPropertyKey new property key - * @param drillVertex true, if vertices shall be drilled, false for edges + * @param label label of the element whose property shall be drilled + * @param propertyKey property key + * @param vertexDrillFunction drill function which shall be applied to a property of a vertex + * @param edgeDrillFunction drill function which shall be applied to a property of an edge + * @param graphheadDrillFunction drill function which shall be applied to a property of a + * graph head + * @param newPropertyKey new property key + * @param element Element to be covered by the operation */ - DrillUp(String label, String propertyKey, DrillFunction function, String newPropertyKey, - boolean drillVertex) { - super(label, propertyKey, function, newPropertyKey, drillVertex); + RollUp(String label, String propertyKey, DrillFunction vertexDrillFunction, + DrillFunction edgeDrillFunction, DrillFunction graphheadDrillFunction, + String newPropertyKey, Element element) { + super(label, propertyKey, vertexDrillFunction, edgeDrillFunction, graphheadDrillFunction, + newPropertyKey, element); } @Override public LogicalGraph execute(LogicalGraph graph) { - if (drillVertex()) { + switch (getElement()) { + case VERTICES: graph = graph.transformVertices( - new DrillUpTransformation(getLabel(), getPropertyKey(), getFunction(), - getNewPropertyKey(), drillAllLabels(), keepCurrentPropertyKey())); - } else { + new RollUpTransformation<>( + getLabel(), + getPropertyKey(), + getVertexDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + case EDGES: graph = graph.transformEdges( - new DrillUpTransformation(getLabel(), getPropertyKey(), getFunction(), - getNewPropertyKey(), drillAllLabels(), keepCurrentPropertyKey())); + new RollUpTransformation<>( + getLabel(), + getPropertyKey(), + getEdgeDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + case GRAPHHEAD: + graph = graph.transformGraphHead( + new RollUpTransformation<>( + getLabel(), + getPropertyKey(), + getGraphheadDrillFunction(), + getNewPropertyKey(), + drillAllLabels(), + keepCurrentPropertyKey())); + break; + default: + throw new UnsupportedTypeException("Element type must be vertex, edge or graphhead"); } return graph; } @Override public String getName() { - return DrillUp.class.getName(); + return RollUp.class.getName(); } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillDownTransformation.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillDownTransformation.java index f1ae320e99fd..c53a56ceb58e 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillDownTransformation.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillDownTransformation.java @@ -55,7 +55,7 @@ public EL apply(EL current, EL transformed) { // drill up was stored with the same label if (keepCurrentPropertyKey()) { // get the last used number in the roll up step - int i = getNextDrillUpVersionNumber(current) - 1; + int i = getNextRollUpVersionNumber(current) - 1; // save the property on the next level to the key transformed.setProperty(getPropertyKey(), current.getPropertyValue(getPropertyKey() + PROPERTY_VERSION_SEPARATOR + i)); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillTransformation.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillTransformation.java index e61197545989..2e4ad85dd2e0 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillTransformation.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillTransformation.java @@ -84,7 +84,7 @@ public DrillTransformation(String label, String propertyKey, DrillFunction funct * @param element element whose property shall be drilled up * @return next unused version number */ - protected int getNextDrillUpVersionNumber(EL element) { + protected int getNextRollUpVersionNumber(EL element) { int i = 1; while (element.hasProperty(getPropertyKey() + PROPERTY_VERSION_SEPARATOR + i)) { i++; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillUpTransformation.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/RollUpTransformation.java similarity index 81% rename from gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillUpTransformation.java rename to gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/RollUpTransformation.java index 8787b4bbf0fc..8b816ed565d3 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/DrillUpTransformation.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/drilling/functions/transformations/RollUpTransformation.java @@ -19,24 +19,24 @@ import org.gradoop.flink.model.impl.operators.drilling.functions.drillfunctions.DrillFunction; /** - * Logical graph transformation which drills up a property value of a given key. This class is + * Logical graph transformation which rolls up a property value of a given key. This class is * used for vertices and edges. * * @param element */ -public class DrillUpTransformation extends DrillTransformation { +public class RollUpTransformation extends DrillTransformation { /** * Valued constructor. * - * @param label label of the element whose property shall be drilled + * @param label label of the element whose property shall be rolled * @param propertyKey property key * @param function drill function which shall be applied to a property * @param newPropertyKey new property key - * @param drillAllLabels true, if all elements of a kind (vertex / edge) shall be drilled + * @param drillAllLabels true, if all elements of an element shall be drilled * @param keepCurrentPropertyKey true, if the current property key shall be reused */ - public DrillUpTransformation(String label, String propertyKey, DrillFunction function, + public RollUpTransformation(String label, String propertyKey, DrillFunction function, String newPropertyKey, boolean drillAllLabels, boolean keepCurrentPropertyKey) { super(label, propertyKey, function, newPropertyKey, drillAllLabels, keepCurrentPropertyKey); } @@ -49,19 +49,19 @@ public EL apply(EL current, EL transformed) { // filters relevant elements if (drillAllLabels() || getLabel().equals(current.getLabel())) { if (current.hasProperty(getPropertyKey())) { - // save drilled up value with the same key + // save rolled up value with the same key if (keepCurrentPropertyKey()) { // save the original value with the version number in the property key transformed.setProperty( - getPropertyKey() + PROPERTY_VERSION_SEPARATOR + getNextDrillUpVersionNumber(current), + getPropertyKey() + PROPERTY_VERSION_SEPARATOR + getNextRollUpVersionNumber(current), current.getPropertyValue(getPropertyKey())); - // save the new drilled value + // save the new rolled value transformed.setProperty( getPropertyKey(), getFunction().execute(current.getPropertyValue(getPropertyKey()))); // new key is used, so the old property is untouched } else { - // store the drilled value with the new key + // store the rolled value with the new key transformed.setProperty( getNewPropertyKey(), getFunction().execute(current.getPropertyValue(getPropertyKey()))); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/equality/CollectionEqualityByGraphIds.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/equality/CollectionEqualityByGraphIds.java index 586aa61d389a..e2651ae483cc 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/equality/CollectionEqualityByGraphIds.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/equality/CollectionEqualityByGraphIds.java @@ -24,7 +24,7 @@ import org.gradoop.flink.model.impl.functions.bool.Not; import org.gradoop.flink.model.impl.functions.bool.Or; import org.gradoop.flink.model.impl.functions.epgm.Id; -import org.gradoop.flink.model.impl.functions.tuple.ValueInTuple1; +import org.gradoop.flink.model.impl.functions.tuple.ObjectTo1; import org.gradoop.flink.model.impl.functions.utils.OneSideEmpty; /** @@ -41,13 +41,13 @@ public DataSet execute(GraphCollection firstCollection, .getGraphHeads() .map(new Id()) .distinct() - .map(new ValueInTuple1()); + .map(new ObjectTo1<>()); DataSet> distinctSecondGraphIds = secondCollection .getGraphHeads() .map(new Id()) .distinct() - .map(new ValueInTuple1()); + .map(new ObjectTo1<>()); DataSet d = distinctFirstGraphIds .fullOuterJoin(distinctSecondGraphIds) diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSampling.java index 48411ebba843..758c5f1e7b40 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSampling.java @@ -19,7 +19,6 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.epgm.Id; import org.gradoop.flink.model.impl.functions.epgm.SourceId; import org.gradoop.flink.model.impl.functions.epgm.TargetId; @@ -31,7 +30,7 @@ * and their associated source- and target-vertices. No unconnected vertices will retain in the * sampled graph. */ -public class RandomEdgeSampling implements UnaryGraphToGraphOperator { +public class RandomEdgeSampling extends SamplingAlgorithm { /** * Relative amount of edges in the result graph */ @@ -46,7 +45,7 @@ public class RandomEdgeSampling implements UnaryGraphToGraphOperator { /** * Creates new RandomEdgeSampling instance. * - * @param sampleSize relative preprocess size + * @param sampleSize relative sample size, e.g. 0.5 */ public RandomEdgeSampling(float sampleSize) { this(sampleSize, 0L); @@ -55,7 +54,7 @@ public RandomEdgeSampling(float sampleSize) { /** * Creates new RandomEdgeSampling instance. * - * @param sampleSize relative sample size + * @param sampleSize relative sample size, e.g. 0.5 * @param randomSeed random seed value (can be 0) */ public RandomEdgeSampling(float sampleSize, long randomSeed) { @@ -67,17 +66,20 @@ public RandomEdgeSampling(float sampleSize, long randomSeed) { * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { - DataSet newEdges = - graph.getEdges().filter(new RandomFilter<>(sampleSize, randomSeed)); + public LogicalGraph sample(LogicalGraph graph) { + DataSet newEdges = graph.getEdges().filter(new RandomFilter<>(sampleSize, randomSeed)); - DataSet newSourceVertices = - graph.getVertices().join(newEdges).where(new Id<>()).equalTo(new SourceId<>()) - .with(new LeftSide<>()).distinct(new Id<>()); + DataSet newSourceVertices = graph.getVertices() + .join(newEdges) + .where(new Id<>()).equalTo(new SourceId<>()) + .with(new LeftSide<>()) + .distinct(new Id<>()); - DataSet newTargetVertices = - graph.getVertices().join(newEdges).where(new Id<>()).equalTo(new TargetId<>()) - .with(new LeftSide<>()).distinct(new Id<>()); + DataSet newTargetVertices = graph.getVertices() + .join(newEdges) + .where(new Id<>()).equalTo(new TargetId<>()) + .with(new LeftSide<>()) + .distinct(new Id<>()); DataSet newVertices = newSourceVertices.union(newTargetVertices).distinct(new Id<>()); return graph.getConfig().getLogicalGraphFactory().fromDataSets(newVertices, newEdges); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSampling.java index d25c66cdfc44..30daea7f8498 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSampling.java @@ -20,7 +20,6 @@ import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.algorithms.gelly.vertexdegrees.DistinctVertexDegrees; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.epgm.Id; import org.gradoop.flink.model.impl.functions.epgm.PropertyRemover; import org.gradoop.flink.model.impl.functions.epgm.SourceId; @@ -34,7 +33,7 @@ * degree threshold and degree type. Also retains randomly chosen vertices with a degree smaller * or equal this threshold. Retains all edges which source- and target-vertices where chosen. */ -public class RandomLimitedDegreeVertexSampling implements UnaryGraphToGraphOperator { +public class RandomLimitedDegreeVertexSampling extends SamplingAlgorithm { /** * Relative amount of vertices in the result graph @@ -78,7 +77,7 @@ public RandomLimitedDegreeVertexSampling(float sampleSize, long randomSeed) { this.sampleSize = sampleSize; this.randomSeed = randomSeed; this.degreeThreshold = 2L; - this.degreeType = VertexDegree.IN_OUT; + this.degreeType = VertexDegree.BOTH; } /** @@ -116,20 +115,20 @@ public RandomLimitedDegreeVertexSampling(float sampleSize, long degreeThreshold, * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { + public LogicalGraph sample(LogicalGraph graph) { graph = new DistinctVertexDegrees( - VertexDegree.IN_OUT.getName(), - VertexDegree.IN.getName(), - VertexDegree.OUT.getName(), + DEGREE_PROPERTY_KEY, + IN_DEGREE_PROPERTY_KEY, + OUT_DEGREE_PROPERTY_KEY, true).execute(graph); DataSet newVertices = graph.getVertices() .filter(new LimitedDegreeVertexRandomFilter<>( sampleSize, randomSeed, degreeThreshold, degreeType)) - .map(new PropertyRemover<>(VertexDegree.IN_OUT.getName())) - .map(new PropertyRemover<>(VertexDegree.IN.getName())) - .map(new PropertyRemover<>(VertexDegree.OUT.getName())); + .map(new PropertyRemover<>(DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(IN_DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(OUT_DEGREE_PROPERTY_KEY)); DataSet newEdges = graph.getEdges() .join(newVertices) diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSampling.java index 520a00b81da9..897e4137475b 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSampling.java @@ -20,7 +20,6 @@ import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.algorithms.gelly.vertexdegrees.DistinctVertexDegrees; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.epgm.Id; import org.gradoop.flink.model.impl.functions.epgm.PropertyRemover; import org.gradoop.flink.model.impl.functions.epgm.SourceId; @@ -28,7 +27,6 @@ import org.gradoop.flink.model.impl.functions.utils.LeftSide; import org.gradoop.flink.model.impl.operators.sampling.functions.AddMaxDegreeCrossFunction; import org.gradoop.flink.model.impl.operators.sampling.functions.NonUniformVertexRandomFilter; -import org.gradoop.flink.model.impl.operators.sampling.functions.VertexDegree; import org.gradoop.flink.model.impl.operators.sampling.functions.VertexToDegreeMap; /** @@ -37,7 +35,8 @@ * is taken into account to have a bias towards high-degree vertices. There may retain some * unconnected vertices in the sampled graph. */ -public class RandomNonUniformVertexSampling implements UnaryGraphToGraphOperator { +public class RandomNonUniformVertexSampling extends SamplingAlgorithm { + /** * Relative amount of vertices in the result graph */ @@ -73,35 +72,31 @@ public RandomNonUniformVertexSampling(float sampleSize, long randomSeed) { * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { - String degreePropertyName = VertexDegree.IN_OUT.getName(); - String inDegreePropertyName = VertexDegree.IN.getName(); - String outDegreePropertyName = VertexDegree.OUT.getName(); - String maxDegree = "_maxDegree"; + public LogicalGraph sample(LogicalGraph graph) { graph = new DistinctVertexDegrees( - degreePropertyName, - inDegreePropertyName, - outDegreePropertyName, + DEGREE_PROPERTY_KEY, + IN_DEGREE_PROPERTY_KEY, + OUT_DEGREE_PROPERTY_KEY, true).execute(graph); DataSet newVertices = graph.getVertices() - .map(new VertexToDegreeMap(degreePropertyName)) + .map(new VertexToDegreeMap(DEGREE_PROPERTY_KEY)) .max(0) .cross(graph.getVertices()) - .with(new AddMaxDegreeCrossFunction(maxDegree)); + .with(new AddMaxDegreeCrossFunction(PROPERTY_KEY_MAX_DEGREE)); graph = graph.getConfig().getLogicalGraphFactory() .fromDataSets(graph.getGraphHead(), newVertices, graph.getEdges()); newVertices = graph.getVertices().filter(new NonUniformVertexRandomFilter<>( - sampleSize, randomSeed, degreePropertyName, maxDegree)); + sampleSize, randomSeed, DEGREE_PROPERTY_KEY, PROPERTY_KEY_MAX_DEGREE)); newVertices = newVertices - .map(new PropertyRemover<>(degreePropertyName)) - .map(new PropertyRemover<>(inDegreePropertyName)) - .map(new PropertyRemover<>(outDegreePropertyName)) - .map(new PropertyRemover<>(maxDegree)); + .map(new PropertyRemover<>(DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(IN_DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(OUT_DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(PROPERTY_KEY_MAX_DEGREE)); DataSet newEdges = graph.getEdges() .join(newVertices) diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSampling.java index 5708869af614..9c803e9a0fe5 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSampling.java @@ -16,9 +16,6 @@ package org.gradoop.flink.model.impl.operators.sampling; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; - -import java.security.InvalidParameterException; /** * Computes an edge sampling of the graph. First selects randomly chosen vertices of a given @@ -26,10 +23,10 @@ * chooses edges from this set of edges and their associated source- and target-vertices. * No unconnected vertices will retain in the sampled graph. */ -public class RandomVertexEdgeSampling implements UnaryGraphToGraphOperator { +public class RandomVertexEdgeSampling extends SamplingAlgorithm { /** - * The samping type enum + * The sampling type enum */ public enum VertexEdgeSamplingType { /** @@ -119,21 +116,25 @@ public RandomVertexEdgeSampling(float vertexSampleSize, float edgeSampleSize, lo * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { - if (vertexEdgeSamplingType == VertexEdgeSamplingType.SimpleVersion) { + public LogicalGraph sample(LogicalGraph graph) { + + switch (vertexEdgeSamplingType) { + case SimpleVersion: graph = new RandomVertexSampling(vertexSampleSize, randomSeed).execute(graph); graph = new RandomEdgeSampling(edgeSampleSize, randomSeed).execute(graph); - } else if (vertexEdgeSamplingType == VertexEdgeSamplingType.NonuniformVersion || - vertexEdgeSamplingType == VertexEdgeSamplingType.NonuniformHybridVersion) { + break; + case NonuniformVersion: + graph = new RandomNonUniformVertexSampling(vertexSampleSize, randomSeed).execute(graph); + graph = new RandomEdgeSampling(edgeSampleSize, randomSeed).execute(graph); + break; + case NonuniformHybridVersion: graph = new RandomNonUniformVertexSampling(vertexSampleSize, randomSeed).execute(graph); - if (vertexEdgeSamplingType == VertexEdgeSamplingType.NonuniformHybridVersion) { - graph = new RandomEdgeSampling(1 - vertexSampleSize, randomSeed).execute(graph); - } else { - graph = new RandomEdgeSampling(edgeSampleSize, randomSeed).execute(graph); - } - } else { - throw new InvalidParameterException(); + graph = new RandomEdgeSampling(1 - vertexSampleSize, randomSeed).execute(graph); + break; + default: + break; } + return graph; } @@ -144,24 +145,4 @@ public LogicalGraph execute(LogicalGraph graph) { public String getName() { return RandomVertexEdgeSampling.class.getName(); } - - /** - * Converts a string to sample type - * - * @param type the string containing the sample type - * @return the actual type of sampling - */ - public static VertexEdgeSamplingType sampleTypeFromString(String type) { - VertexEdgeSamplingType vertexEdgeSamplingType; - if (type.equals(RandomVertexEdgeSampling.VertexEdgeSamplingType.SimpleVersion.toString())) { - vertexEdgeSamplingType = VertexEdgeSamplingType.SimpleVersion; - } else if (type.equals(VertexEdgeSamplingType.NonuniformVersion.toString())) { - vertexEdgeSamplingType = VertexEdgeSamplingType.NonuniformVersion; - } else if (type.equals(VertexEdgeSamplingType.NonuniformHybridVersion.toString())) { - vertexEdgeSamplingType = VertexEdgeSamplingType.NonuniformHybridVersion; - } else { - throw new InvalidParameterException(); - } - return vertexEdgeSamplingType; - } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSampling.java index 8932bc548c6d..6e416b295b62 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSampling.java @@ -22,7 +22,6 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.tuple.Value0Of3; import org.gradoop.flink.model.impl.operators.sampling.functions.EdgeWithSourceTarget; import org.gradoop.flink.model.impl.operators.sampling.functions.Neighborhood; @@ -38,7 +37,7 @@ * amount and includes all neighbors of those vertices in the sampling. All edges which source- * and target-vertices where chosen are sampled, too. */ -public class RandomVertexNeighborhoodSampling implements UnaryGraphToGraphOperator { +public class RandomVertexNeighborhoodSampling extends SamplingAlgorithm { /** * Relative amount of vertices in the result graph @@ -54,7 +53,7 @@ public class RandomVertexNeighborhoodSampling implements UnaryGraphToGraphOperat /** * Type of degree which should be considered: input degree, output degree, sum of both. */ - private final Neighborhood.NeighborType neighborType; + private final Neighborhood neighborType; /** * Creates new RandomVertexNeighborhoodSampling instance. @@ -74,7 +73,7 @@ public RandomVertexNeighborhoodSampling(float sampleSize) { public RandomVertexNeighborhoodSampling(float sampleSize, long randomSeed) { this.sampleSize = sampleSize; this.randomSeed = randomSeed; - this.neighborType = Neighborhood.NeighborType.Both; + this.neighborType = Neighborhood.BOTH; } /** @@ -85,7 +84,7 @@ public RandomVertexNeighborhoodSampling(float sampleSize, long randomSeed) { * @param neighborType type of neighbor-vertex for sampling */ public RandomVertexNeighborhoodSampling(float sampleSize, long randomSeed, - Neighborhood.NeighborType neighborType) { + Neighborhood neighborType) { this.sampleSize = sampleSize; this.randomSeed = randomSeed; this.neighborType = neighborType; @@ -98,7 +97,7 @@ public RandomVertexNeighborhoodSampling(float sampleSize, long randomSeed, * @param neighborType type of neighbor-vertex for sampling */ public RandomVertexNeighborhoodSampling(float sampleSize, - Neighborhood.NeighborType neighborType) { + Neighborhood neighborType) { this.sampleSize = sampleSize; this.randomSeed = 0L; this.neighborType = neighborType; @@ -108,27 +107,25 @@ public RandomVertexNeighborhoodSampling(float sampleSize, * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { - String propertyNameForSampled = "sampled"; - + public LogicalGraph sample(LogicalGraph graph) { DataSet> sampledVerticesWithId = graph.getVertices() - .map(new VertexRandomMarkedMap<>(sampleSize, randomSeed, propertyNameForSampled)) - .map(new VertexWithId()); + .map(new VertexRandomMarkedMap<>(sampleSize, randomSeed, PROPERTY_KEY_SAMPLED)) + .map(new VertexWithId()); DataSet> edgeSourceIdTargetId = graph.getEdges() - .map(new EdgeWithSourceTarget()); - - DataSet ds = edgeSourceIdTargetId - .join(sampledVerticesWithId) - .where(1).equalTo(1) - .with(new EdgeSourceVertexJoin()) - .join(sampledVerticesWithId) - .where(2).equalTo(1) - .with(new EdgeTargetVertexJoin()) - .filter(new EdgesWithSampledVerticesFilter(propertyNameForSampled, neighborType)) - .map(new Value0Of3<>()); - - graph = graph.getConfig().getLogicalGraphFactory().fromDataSets(graph.getVertices(), ds); + .map(new EdgeWithSourceTarget()); + + DataSet newEdges = edgeSourceIdTargetId + .join(sampledVerticesWithId) + .where(1).equalTo(1) + .with(new EdgeSourceVertexJoin()) + .join(sampledVerticesWithId) + .where(2).equalTo(1) + .with(new EdgeTargetVertexJoin()) + .filter(new EdgesWithSampledVerticesFilter(PROPERTY_KEY_SAMPLED, neighborType)) + .map(new Value0Of3<>()); + + graph = graph.getConfig().getLogicalGraphFactory().fromDataSets(graph.getVertices(), newEdges); graph = new FilterVerticesWithDegreeOtherThanGiven(0L).execute(graph); return graph; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSampling.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSampling.java index d4d04daeb4d8..e6f3d7138f6d 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSampling.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSampling.java @@ -19,7 +19,6 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.epgm.Id; import org.gradoop.flink.model.impl.functions.epgm.SourceId; import org.gradoop.flink.model.impl.functions.epgm.TargetId; @@ -31,7 +30,7 @@ * aggregate function is applied on the logical graph and the resulting * aggregate is stored as an additional property at the result graph. */ -public class RandomVertexSampling implements UnaryGraphToGraphOperator { +public class RandomVertexSampling extends SamplingAlgorithm { /** * Relative amount of nodes in the result graph */ @@ -67,19 +66,17 @@ public RandomVertexSampling(float sampleSize, long randomSeed) { * {@inheritDoc} */ @Override - public LogicalGraph execute(LogicalGraph graph) { + public LogicalGraph sample(LogicalGraph graph) { DataSet newVertices = graph.getVertices() .filter(new RandomFilter<>(sampleSize, randomSeed)); DataSet newEdges = graph.getEdges() .join(newVertices) - .where(new SourceId<>()) - .equalTo(new Id<>()) + .where(new SourceId<>()).equalTo(new Id<>()) .with(new LeftSide<>()) .join(newVertices) - .where(new TargetId<>()) - .equalTo(new Id<>()) + .where(new TargetId<>()).equalTo(new Id<>()) .with(new LeftSide<>()); return graph.getConfig().getLogicalGraphFactory().fromDataSets(newVertices, newEdges); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/SamplingAlgorithm.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/SamplingAlgorithm.java new file mode 100644 index 000000000000..11ae1a8f8bb7 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/SamplingAlgorithm.java @@ -0,0 +1,68 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.model.impl.operators.sampling; + +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.gradoop.flink.model.impl.operators.sampling.functions.FilterVerticesWithDegreeOtherThanGiven; +import org.gradoop.flink.model.impl.operators.sampling.functions.VertexDegree; + +/** + * Abstract class to provide property keys and methods for sampling algorithms. + */ +public abstract class SamplingAlgorithm implements UnaryGraphToGraphOperator { + + /** + * Key of degree property, used by {@link RandomNonUniformVertexSampling}, + * {@link RandomLimitedDegreeVertexSampling} and {@link FilterVerticesWithDegreeOtherThanGiven} + */ + public static final String DEGREE_PROPERTY_KEY = VertexDegree.BOTH.getName(); + + /** + * Key of in-degree property, used by {@link RandomNonUniformVertexSampling}, + * {@link RandomLimitedDegreeVertexSampling} and {@link FilterVerticesWithDegreeOtherThanGiven} + */ + public static final String IN_DEGREE_PROPERTY_KEY = VertexDegree.IN.getName(); + + /** + * Key of out-degree property, used by {@link RandomNonUniformVertexSampling}, + * {@link RandomLimitedDegreeVertexSampling} and {@link FilterVerticesWithDegreeOtherThanGiven} + */ + public static final String OUT_DEGREE_PROPERTY_KEY = VertexDegree.OUT.getName(); + + /** + * Key of a property generated by {@link RandomVertexNeighborhoodSampling} + */ + static final String PROPERTY_KEY_SAMPLED = "sampled"; + + /** + * Key of a property generated by {@link RandomNonUniformVertexSampling} + */ + static final String PROPERTY_KEY_MAX_DEGREE = "_maxDegree"; + + @Override + public LogicalGraph execute(LogicalGraph graph) { + return sample(graph); + } + + /** + * Each sampling method should prepare a sample method + * + * @param graph graph that will be sampled of + * @return sampled graph + */ + protected abstract LogicalGraph sample(LogicalGraph graph); +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/EdgesWithSampledVerticesFilter.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/EdgesWithSampledVerticesFilter.java index d6f48b096079..a2670297620b 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/EdgesWithSampledVerticesFilter.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/EdgesWithSampledVerticesFilter.java @@ -21,11 +21,11 @@ import org.gradoop.common.model.impl.pojo.Vertex; /** - * Filters the edges with sampled vertices - * If any vertices of the edge does not have any related property for sampling, - * we consider that vertex as not sampled. + * Filters the edges with sampled vertices. If any vertices of the edge does not have any related + * property for sampling, we consider that vertex as not sampled. */ -public class EdgesWithSampledVerticesFilter implements FilterFunction> { +public class EdgesWithSampledVerticesFilter + implements FilterFunction> { /** * Property name which shows if a vertex is sampled */ @@ -33,7 +33,7 @@ public class EdgesWithSampledVerticesFilter implements FilterFunction t3) { t3.f2.getPropertyValue(propertyNameForSampled).toString()); } boolean ret = false; - if (neighborType.equals(Neighborhood.NeighborType.Both)) { + if (neighborType.equals(Neighborhood.BOTH)) { ret = isSourceVertexMarked || isTargetVertexMarked; - } else if (neighborType.equals(Neighborhood.NeighborType.Input)) { + } else if (neighborType.equals(Neighborhood.IN)) { ret = isTargetVertexMarked; - } else if (neighborType.equals(Neighborhood.NeighborType.Output)) { + } else if (neighborType.equals(Neighborhood.OUT)) { ret = isSourceVertexMarked; } return ret; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/FilterVerticesWithDegreeOtherThanGiven.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/FilterVerticesWithDegreeOtherThanGiven.java index 920e4e85ecee..746fcd80622c 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/FilterVerticesWithDegreeOtherThanGiven.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/FilterVerticesWithDegreeOtherThanGiven.java @@ -21,6 +21,7 @@ import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.functions.epgm.PropertyRemover; +import org.gradoop.flink.model.impl.operators.sampling.SamplingAlgorithm; /** * Retains all vertices which do not have the given degree. @@ -47,17 +48,16 @@ public FilterVerticesWithDegreeOtherThanGiven(long degree) { @Override public LogicalGraph execute(LogicalGraph graph) { DistinctVertexDegrees distinctVertexDegrees = new DistinctVertexDegrees( - VertexDegree.IN_OUT.getName(), - VertexDegree.IN.getName(), - VertexDegree.OUT.getName(), + SamplingAlgorithm.DEGREE_PROPERTY_KEY, + SamplingAlgorithm.IN_DEGREE_PROPERTY_KEY, + SamplingAlgorithm.OUT_DEGREE_PROPERTY_KEY, true); - DataSet newVertices = distinctVertexDegrees.execute(graph).getVertices(); - newVertices = newVertices.filter( - new VertexWithDegreeFilter<>(degree, VertexDegree.IN_OUT.getName())) - .map(new PropertyRemover<>(VertexDegree.IN_OUT.getName())) - .map(new PropertyRemover<>(VertexDegree.IN.getName())) - .map(new PropertyRemover<>(VertexDegree.OUT.getName())); + DataSet newVertices = distinctVertexDegrees.execute(graph).getVertices() + .filter(new VertexWithDegreeFilter<>(degree, SamplingAlgorithm.DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(SamplingAlgorithm.DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(SamplingAlgorithm.IN_DEGREE_PROPERTY_KEY)) + .map(new PropertyRemover<>(SamplingAlgorithm.OUT_DEGREE_PROPERTY_KEY)); return graph.getConfig().getLogicalGraphFactory().fromDataSets( graph.getGraphHead(), newVertices, graph.getEdges()); diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/Neighborhood.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/Neighborhood.java index dc7fa27ddff2..c6e956130347 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/Neighborhood.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/Neighborhood.java @@ -15,44 +15,45 @@ */ package org.gradoop.flink.model.impl.operators.sampling.functions; -import java.security.InvalidParameterException; - /** - * Keeps the types of neighborhood + * Keeps the types of vertex-neighborhood regarding the connecting edges + * and their respective property names. + * Available neighborhood-types: input (IN), output (OUT), both (BOTH). */ -public class Neighborhood { +public enum Neighborhood { + /** + * Input edges + */ + IN("_InNeighbor"), + /** + * Output edges + */ + OUT("_OutNeighbor"), + /** + * Both edges + */ + BOTH("_InOutNeighbor"); + + /** + * The property name of a vertex neighbor type + */ + private String neighborPropertyName; + /** - * Types of neighborhood: input, output, or both edges + * Enum constructor for neighbor type with property name. + * + * @param neighborPropertyName The property name for a neighbor type */ - public enum NeighborType { - /** - * Input edges - */ - Input, - /** - * Output edges - */ - Output, - /** - * Both edges - */ - Both + Neighborhood(String neighborPropertyName) { + this.neighborPropertyName = neighborPropertyName; } /** - * Build an instance of NieghborType from a given string - * @param neighborType type of neighborhood - * @return an instace of NieghborType + * Get the property name for an instance of Neighborhood. + * + * @return The neighbor property name */ - public static NeighborType fromString(String neighborType) { - if (neighborType.equals(NeighborType.Input.toString())) { - return NeighborType.Input; - } else if (neighborType.equals(NeighborType.Output.toString())) { - return NeighborType.Output; - } else if (neighborType.equals(NeighborType.Both.toString())) { - return NeighborType.Both; - } else { - throw new InvalidParameterException(); - } + public String getName() { + return neighborPropertyName; } } diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/VertexDegree.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/VertexDegree.java index 31142eb5411a..c17d7d350e24 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/VertexDegree.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/functions/VertexDegree.java @@ -17,7 +17,7 @@ /** * Keeps the types of vertex-degrees and their respective property names. - * Available degree-types: input (IN), output (OUT), sum of both (IN_OUT). + * Available degree-types: input (IN), output (OUT), sum of both (BOTH). */ public enum VertexDegree { /** @@ -31,7 +31,7 @@ public enum VertexDegree { /** * The sum of input and output degree */ - IN_OUT("_InOutDegree"); + BOTH("_Degree"); /** * The property name of a vertex degree type diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensity.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensity.java new file mode 100644 index 000000000000..e619529aee36 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensity.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics; + +import org.apache.flink.api.java.DataSet; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.gradoop.flink.model.impl.operators.aggregation.functions.count.EdgeCount; +import org.gradoop.flink.model.impl.operators.aggregation.functions.count.VertexCount; +import org.gradoop.flink.model.impl.operators.sampling.statistics.functions.CalculateDensity; + +/** + * Computes the density of a graph and writes it to the graph head. + * Uses: (|E|) / (|V| * (|V| - 1)) + */ +public class GraphDensity implements UnaryGraphToGraphOperator { + + /** + * {@inheritDoc} + */ + @Override + public LogicalGraph execute(LogicalGraph graph) { + DataSet newGraphHead = graph + .aggregate(new VertexCount()) + .aggregate(new EdgeCount()) + .getGraphHead() + .map(new CalculateDensity(SamplingEvaluationConstants.PROPERTY_KEY_DENSITY)); + + return graph.getConfig().getLogicalGraphFactory() + .fromDataSets(newGraphHead, graph.getVertices(), graph.getEdges()); + } + + @Override + public String getName() { + return GraphDensity.class.getName(); + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/SamplingEvaluationConstants.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/SamplingEvaluationConstants.java new file mode 100644 index 000000000000..484011151f60 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/SamplingEvaluationConstants.java @@ -0,0 +1,37 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics; + +/** + * Collected constants for sampling evaluation + */ +public class SamplingEvaluationConstants { + + /** + * Key for density property generated by {@link GraphDensity} + */ + public static final String PROPERTY_KEY_DENSITY = "density"; + + /** + * Filename for the saved density value of the graph + */ + public static final String FILE_DENSITY = "graph_density"; + + /** + * private Constructor + */ + private SamplingEvaluationConstants() { } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/CalculateDensity.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/CalculateDensity.java new file mode 100644 index 000000000000..971bc1b5cebf --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/CalculateDensity.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics.functions; + +import org.apache.flink.api.common.functions.MapFunction; +import org.gradoop.common.model.impl.pojo.GraphHead; + +/** + * Calculates the graph density and safes the value as property to the corresponding graphHead. + */ +public class CalculateDensity implements MapFunction { + + /** + * Used property key + */ + private String propertyKey; + + /** + * Public constructor + * + * @param key used property key + */ + public CalculateDensity(String key) { + this.propertyKey = key; + } + + /** + * Calculates the graph density and safes the value as property to the graphHead. + * + * @param graphHead The graphHead the density shall be written to + * @return GraphHead The graphHead the density is written to + */ + @Override + public GraphHead map(GraphHead graphHead) { + double vc1 = (double) graphHead.getPropertyValue("vertexCount").getLong(); + double ec1 = (double) graphHead.getPropertyValue("edgeCount").getLong(); + double density = ec1 / (vc1 * (vc1 - 1.)); + graphHead.setProperty(propertyKey, density); + return graphHead; + } +} diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/package-info.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/package-info.java new file mode 100644 index 000000000000..554c40b672a7 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/functions/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains sampling statistics functions + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics.functions; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/package-info.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/package-info.java new file mode 100644 index 000000000000..fb6fc42a4d83 --- /dev/null +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/sampling/statistics/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains a collection of evaluation methods for graph sampling. + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics; diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/subgraph/Subgraph.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/subgraph/Subgraph.java index d301373595fa..6a18c51781b8 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/subgraph/Subgraph.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/subgraph/Subgraph.java @@ -27,9 +27,9 @@ import org.gradoop.flink.model.impl.functions.epgm.Id; import org.gradoop.flink.model.impl.functions.epgm.SourceId; import org.gradoop.flink.model.impl.functions.epgm.TargetId; +import org.gradoop.flink.model.impl.functions.tuple.ObjectTo1; import org.gradoop.flink.model.impl.functions.tuple.Value0Of2; import org.gradoop.flink.model.impl.functions.tuple.Value1Of2; -import org.gradoop.flink.model.impl.functions.tuple.ValueInTuple1; import org.gradoop.flink.model.impl.functions.utils.LeftSide; import org.gradoop.flink.model.impl.functions.utils.RightSide; @@ -220,10 +220,10 @@ private LogicalGraph edgeInducedSubgraphProjectFirst(LogicalGraph superGraph) { DataSet> vertexIdentifiers = filteredEdges .map(new SourceId<>()) - .map(new ValueInTuple1<>()) + .map(new ObjectTo1<>()) .union(filteredEdges .map(new TargetId<>()) - .map(new ValueInTuple1<>())) + .map(new ObjectTo1<>())) .distinct(); DataSet filteredVertices = vertexIdentifiers diff --git a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/tostring/api/VertexToString.java b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/tostring/api/VertexToString.java index a3f726a99e6c..2faa477187c7 100644 --- a/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/tostring/api/VertexToString.java +++ b/gradoop-flink/src/main/java/org/gradoop/flink/model/impl/operators/tostring/api/VertexToString.java @@ -21,8 +21,8 @@ /** * string representation of a vertex - * @param graph head type + * + * @param vertex type */ -public interface VertexToString - extends FlatMapFunction { +public interface VertexToString extends FlatMapFunction { } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRankTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRankTest.java new file mode 100644 index 000000000000..a59b5d1b3a68 --- /dev/null +++ b/gradoop-flink/src/test/java/org/gradoop/flink/algorithms/gelly/pagerank/PageRankTest.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.algorithms.gelly.pagerank; + +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.flink.model.GradoopFlinkTestBase; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +/** + * A test for {@link PageRank}, calling the operator and checking if the result was set. + */ +public class PageRankTest extends GradoopFlinkTestBase { + + /** + * The property key used to store the page rank result. + */ + public static final String PROPERTY_KEY = "pageRank"; + + /** + * Execute the {@link PageRank} operator and check if the property was set for all vertices. + * + * @throws Exception If the execution fails. + */ + @Test + public void testPageRankExecution() throws Exception { + LogicalGraph input = getSocialNetworkLoader().getLogicalGraphByVariable("g0"); + input.print(); + long inputVertexCount = input.getVertices().count(); + LogicalGraph result = new PageRank(PROPERTY_KEY, 0.3, 20).execute(input); + List resultVertices = result.getVertices().collect(); + assertEquals(inputVertexCount, resultVertices.size()); + for (Vertex vertex : resultVertices) { + assertTrue(vertex.hasProperty(PROPERTY_KEY)); + } + } +} \ No newline at end of file diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSinkTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSinkTest.java index f104455292ba..a9a8bf6ab28d 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSinkTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSinkTest.java @@ -143,7 +143,6 @@ public void testWriteExtendedProperties() throws Exception { DataSource csvDataSource = new CSVDataSource(tmpPath, getConfig()); LogicalGraph sourceLogicalGraph = csvDataSource.getLogicalGraph(); - collectAndAssertTrue(logicalGraph.equalsByElementData(sourceLogicalGraph)); collectAndAssertTrue(logicalGraph.equalsByData(sourceLogicalGraph)); sourceLogicalGraph.getEdges().collect().forEach(this::checkProperties); diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSourceTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSourceTest.java index ecd71bb9e57b..b7ddb0092751 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSourceTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVDataSourceTest.java @@ -57,7 +57,6 @@ public void testReadExtendedProperties() throws Exception { DataSource dataSource = new CSVDataSource(csvPath, getConfig()); LogicalGraph sourceLogicalGraph = dataSource.getLogicalGraph(); - collectAndAssertTrue(sourceLogicalGraph.equalsByElementData(expected)); collectAndAssertTrue(sourceLogicalGraph.equalsByData(expected)); dataSource.getLogicalGraph().getEdges().collect() diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVTestBase.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVTestBase.java index 7383ae971efe..0de993b07ad8 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVTestBase.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/csv/CSVTestBase.java @@ -33,7 +33,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -72,6 +74,14 @@ private static Map getPropertyMap() { objectMap.put(stringValue1, PropertyValue.create(12.345)); objectMap.put(stringValue2, PropertyValue.create(67.89)); + Set stringSet = new HashSet<>(); + stringSet.add(stringValue1); + stringSet.add(stringValue2); + + Set intSet = new HashSet<>(); + intSet.add(PropertyValue.create(1234)); + intSet.add(PropertyValue.create(5678)); + Map propertyMap = new HashMap<>(); propertyMap.put(GradoopTestUtils.KEY_0, GradoopTestUtils.BOOL_VAL_1); propertyMap.put(GradoopTestUtils.KEY_1, GradoopTestUtils.INT_VAL_2); @@ -88,6 +98,9 @@ private static Map getPropertyMap() { propertyMap.put(GradoopTestUtils.KEY_c, stringList); propertyMap.put(GradoopTestUtils.KEY_d, intList); propertyMap.put(GradoopTestUtils.KEY_e, GradoopTestUtils.SHORT_VAL_e); + propertyMap.put(GradoopTestUtils.KEY_f, GradoopTestUtils.NULL_VAL_0); + propertyMap.put(GradoopTestUtils.KEY_g, stringSet); + propertyMap.put(GradoopTestUtils.KEY_h, intSet); return Collections.unmodifiableMap(propertyMap); } @@ -142,6 +155,9 @@ protected void checkProperties(EPGMElement epgmElement) { assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_c)); assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_d)); assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_e)); + assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_f)); + assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_g)); + assertTrue(epgmElement.hasProperty(GradoopTestUtils.KEY_h)); // assert that the properties have valid data types assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_0).isBoolean()); @@ -159,6 +175,9 @@ protected void checkProperties(EPGMElement epgmElement) { assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_c).isList()); assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_d).isList()); assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_e).isShort()); + assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_f).isNull()); + assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_g).isSet()); + assertTrue(epgmElement.getPropertyValue(GradoopTestUtils.KEY_h).isSet()); // assert that the properties have valid values assertEquals(epgmElement.getPropertyValue(GradoopTestUtils.KEY_0).getBoolean(), @@ -191,6 +210,12 @@ protected void checkProperties(EPGMElement epgmElement) { PROPERTY_MAP.get(GradoopTestUtils.KEY_d)); assertEquals(epgmElement.getPropertyValue(GradoopTestUtils.KEY_e).getShort(), PROPERTY_MAP.get(GradoopTestUtils.KEY_e)); + assertEquals(epgmElement.getPropertyValue(GradoopTestUtils.KEY_f).getObject(), + PROPERTY_MAP.get(GradoopTestUtils.KEY_f)); + assertEquals(epgmElement.getPropertyValue(GradoopTestUtils.KEY_g).getSet(), + PROPERTY_MAP.get(GradoopTestUtils.KEY_g)); + assertEquals(epgmElement.getPropertyValue(GradoopTestUtils.KEY_h).getSet(), + PROPERTY_MAP.get(GradoopTestUtils.KEY_h)); } /** @@ -214,5 +239,8 @@ protected void checkMetadataCsvLine(String line) { assertTrue(line.contains(GradoopTestUtils.KEY_c + ":list:string")); assertTrue(line.contains(GradoopTestUtils.KEY_d + ":list:int")); assertTrue(line.contains(GradoopTestUtils.KEY_e + ":short")); + assertTrue(line.contains(GradoopTestUtils.KEY_f + ":null")); + assertTrue(line.contains(GradoopTestUtils.KEY_g + ":set:string")); + assertTrue(line.contains(GradoopTestUtils.KEY_h + ":set:int")); } } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/gdl/GDLDataSinkTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/gdl/GDLDataSinkTest.java new file mode 100644 index 000000000000..65cc143ca12f --- /dev/null +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/gdl/GDLDataSinkTest.java @@ -0,0 +1,31 @@ +package org.gradoop.flink.io.impl.gdl; + +import org.gradoop.flink.io.api.DataSink; +import org.gradoop.flink.model.GradoopFlinkTestBase; +import org.gradoop.flink.model.api.epgm.GraphCollection; +import org.gradoop.flink.util.FlinkAsciiGraphLoader; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class GDLDataSinkTest extends GradoopFlinkTestBase { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void testWrite() throws Exception { + FlinkAsciiGraphLoader testLoader = getSocialNetworkLoader(); + GraphCollection expectedCollection = testLoader.getGraphCollectionByVariables("g0","g1","g2","g3"); + + String path = temporaryFolder.getRoot().getPath() + "/graph.gdl"; + DataSink gdlsink = new GDLDataSink(path); + gdlsink.write(expectedCollection, true); + getExecutionEnvironment().execute(); + + FlinkAsciiGraphLoader sinkLoader = getLoaderFromFile(path); + GraphCollection sinkCollection = sinkLoader + .getGraphCollectionByVariables("g0","g1","g2","g3"); + + collectAndAssertTrue(sinkCollection.equalsByGraphElementData(expectedCollection)); + } +} diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSinkTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSinkTest.java index ec0677dbbe16..750043fa0dad 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSinkTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSinkTest.java @@ -20,6 +20,7 @@ import org.gradoop.flink.io.api.DataSink; import org.gradoop.flink.io.api.DataSource; import org.gradoop.flink.model.GradoopFlinkTestBase; +import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.impl.layouts.transactional.tuples.GraphTransaction; import org.junit.Test; @@ -55,6 +56,60 @@ public void testWrite() throws Exception { .equalsByGraphElementData(dataSource2.getGraphCollection())); } + @Test + public void testWriteWithoutEdges() throws Exception { + String tlfFileImport = TLFDataSinkTest.class + .getResource("/data/tlf/io_test_string_without_edges.tlf").getFile(); + + String tlfFileExport = TLFDataSinkTest.class + .getResource("/data/tlf").getFile() + "/io_test_output"; + + // read from inputfile + DataSource dataSource = new TLFDataSource(tlfFileImport, getConfig()); + // write to ouput path + DataSink dataSink = new TLFDataSink(tlfFileExport, getConfig()); + dataSink.write(dataSource.getGraphCollection(), true); + // read from output path + DataSource dataSource2 = new TLFDataSource(tlfFileExport, getConfig()); + + getExecutionEnvironment().execute(); + + // compare original graph and written one + collectAndAssertTrue(dataSource.getGraphCollection() + .equalsByGraphElementData(dataSource2.getGraphCollection())); + } + + @Test + public void testWriteWithoutEdgesWithDictionaries() throws Exception { + String tlfFileImport = TLFDataSinkTest.class + .getResource("/data/tlf/io_test_string_without_edges.tlf").getFile(); + + String tlfFileExport = TLFDataSinkTest.class.getResource("/data/tlf") + .getFile() + "/io_test_output"; + + String tlfVertexDictionaryFileExport = TLFDataSinkTest.class.getResource("/data/tlf") + .getFile() + "/dictionaries/io_test_output_vertex_dictionary"; + + // read from inputfile + DataSource dataSource = new TLFDataSource(tlfFileImport, getConfig()); + GraphCollection input = dataSource.getGraphCollection(); + + // write to ouput path + DataSink dataSink = new TLFDataSink(tlfFileExport, tlfVertexDictionaryFileExport, + "", getConfig()); + dataSink.write(input, true); + + // read from output path + DataSource dataSource2 = new TLFDataSource(tlfFileExport, tlfVertexDictionaryFileExport, + "", getConfig()); + GraphCollection output = dataSource2.getGraphCollection(); + + getExecutionEnvironment().execute(); + + // compare original graph and written one + collectAndAssertTrue(input.equalsByGraphElementData(output)); + } + @Test public void testWriteWithVertexDictionary() throws Exception { String tlfFileImport = TLFDataSinkTest.class @@ -70,10 +125,10 @@ public void testWriteWithVertexDictionary() throws Exception { + "/dictionaries/io_test_output_vertex_dictionary"; // read from inputfile - DataSource dataSource = new TLFDataSource(tlfFileImport, + DataSource dataSource = new TLFDataSource(tlfFileImport, tlfVertexDictionaryFileImport, "", getConfig()); // write to output path - DataSink dataSink = new TLFDataSink(tlfFileExport, + DataSink dataSink = new TLFDataSink(tlfFileExport, tlfVertexDictionaryFileExport, "", getConfig()); dataSink.write(dataSource.getGraphCollection(), true); // read from output path @@ -117,7 +172,7 @@ public void testWriteWithDictionaries() throws Exception { + "/dictionaries/io_test_output_vertex_dictionary"; String tlfEdgeDictionaryFileExport = TLFDataSinkTest.class - .getResource("/data/tlf").getFile() + .getResource("/data/tlf").getFile() + "/dictionaries/io_test_output_edge_dictionary"; // read from inputfile diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSourceTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSourceTest.java index 7e968efeb406..26ddf38d99bf 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSourceTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/io/impl/tlf/TLFDataSourceTest.java @@ -46,6 +46,29 @@ public void testRead() throws Exception { ); } + @Test + public void testReadWithoutEdges() throws Exception { + String tlfFile = TLFDataSinkTest.class + .getResource("/data/tlf/io_test_string_without_edges.tlf").getFile(); + + // create datasource + DataSource dataSource = new TLFDataSource(tlfFile, getConfig()); + // get transactions + DataSet transactions = dataSource.getGraphCollection().getGraphTransactions(); + + String asciiGraphs = "" + + "g1[(v1:A),(v2:B)]" + + "g2[(v1:A),(v2:B)]"; + + FlinkAsciiGraphLoader loader = getLoaderFromString(asciiGraphs); + + collectAndAssertTrue( + loader.getGraphCollectionByVariables("g1","g2").equalsByGraphData( + getConfig().getGraphCollectionFactory().fromTransactions(transactions) + ) + ); + } + @Test public void testReadWithDictionary() throws Exception { String tlfFile = TLFDataSinkTest.class diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/AggregationTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/AggregationTest.java index 680863d6973d..ad48e1f1367a 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/AggregationTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/AggregationTest.java @@ -21,6 +21,8 @@ import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.flink.model.GradoopFlinkTestBase; import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.impl.operators.aggregation.functions.containment.HasEdgeLabel; +import org.gradoop.flink.model.impl.operators.aggregation.functions.containment.HasVertexLabel; import org.gradoop.flink.model.impl.operators.aggregation.functions.count.EdgeCount; import org.gradoop.flink.model.impl.operators.aggregation.functions.count.VertexCount; import org.gradoop.flink.model.impl.operators.aggregation.functions.max.MaxEdgeProperty; @@ -32,8 +34,7 @@ import org.gradoop.flink.util.FlinkAsciiGraphLoader; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class AggregationTest extends GradoopFlinkTestBase { @@ -231,4 +232,84 @@ void assertCounts(EPGMGraphHead graphHead, long expectedVertexCount, long expect graphHead.getPropertyValue( new EdgeCount().getAggregatePropertyKey()).getLong()); } + + @Test + public void testSingleGraphHasEdgeLabelTrue() throws Exception { + LogicalGraph graph = getSocialNetworkLoader().getLogicalGraphByVariable("g2"); + HasVertexLabel hasPerson = new HasVertexLabel("Person"); + graph = graph.aggregate(hasPerson); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasVertexLabel_Person not set", + graphHead.hasProperty(hasPerson.getAggregatePropertyKey())); + assertTrue("Property hasVertexLabel_Person is false, should be true", + graphHead.getPropertyValue(hasPerson.getAggregatePropertyKey()).getBoolean()); + } + + @Test + public void testSingleGraphHasEdgeLabelFalse() throws Exception { + LogicalGraph graph = getSocialNetworkLoader().getLogicalGraphByVariable("g2"); + HasVertexLabel hasNotExistent = new HasVertexLabel("LabelDoesNotExist"); + graph = graph.aggregate(hasNotExistent); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasVertexLabel_LabelDoesNotExist not set", + graphHead.hasProperty(hasNotExistent.getAggregatePropertyKey())); + assertFalse("Property hasVertexLabel_LabelDoesNotExist is true, should be false", + graphHead.getPropertyValue(hasNotExistent.getAggregatePropertyKey()).getBoolean()); + } + + @Test + public void testSingleGraphHasVertexLabelTrue() throws Exception { + LogicalGraph graph = getSocialNetworkLoader().getLogicalGraphByVariable("g2"); + HasEdgeLabel hasKnows = new HasEdgeLabel("knows"); + graph = graph.aggregate(hasKnows); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasEdgeLabel_knows not set", + graphHead.hasProperty(hasKnows.getAggregatePropertyKey())); + assertTrue("Property hasEdgeLabel_knows is false, should be true", + graphHead.getPropertyValue(hasKnows.getAggregatePropertyKey()).getBoolean()); + } + + @Test + public void testSingleGraphHasVertexLabelFalse() throws Exception { + LogicalGraph graph = getSocialNetworkLoader().getLogicalGraphByVariable("g2"); + HasEdgeLabel hasNotExistent = new HasEdgeLabel("LabelDoesNotExist"); + graph = graph.aggregate(hasNotExistent); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasEdgeLabel_LabelDoesNotExist not set", + graphHead.hasProperty(hasNotExistent.getAggregatePropertyKey())); + assertFalse("Property hasEdgeLabel_LabelDoesNotExist is true, should be false", + graphHead.getPropertyValue(hasNotExistent.getAggregatePropertyKey()).getBoolean()); + } + + @Test + public void testEdgelessGraphHasEdgeLabel() throws Exception { + LogicalGraph graph = getLoaderFromString("g0[(v0)(v1)]") + .getLogicalGraphByVariable("g0"); + HasEdgeLabel hasLabel = new HasEdgeLabel("anyLabel"); + graph = graph.aggregate(hasLabel); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasEdgeLabel_anyLabel not set", + graphHead.hasProperty(hasLabel.getAggregatePropertyKey())); + assertNull("Property hasEdgeLabel_anyLabel is not NULL", + graphHead.getPropertyValue(hasLabel.getAggregatePropertyKey()).getObject()); + } + + @Test + public void testSingleGraphHasVertexLabelEmptyString() throws Exception { + LogicalGraph graph = getLoaderFromString("g0[(v0:)-[e0]->(v1:)") + .getLogicalGraphByVariable("g0"); + HasVertexLabel hasLabel = new HasVertexLabel(""); + graph = graph.aggregate(hasLabel); + EPGMGraphHead graphHead = graph.getGraphHead().collect().get(0); + + assertTrue("Property hasVertexLabel_ not set", + graphHead.hasProperty(hasLabel.getAggregatePropertyKey())); + assertFalse("Property hasVertexLabel_ is true, should be false", + graphHead.getPropertyValue(hasLabel.getAggregatePropertyKey()).getBoolean()); + } } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/ApplyAggregationTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/ApplyAggregationTest.java index 4fa8e01d61e6..76d30e556f44 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/ApplyAggregationTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/aggregation/ApplyAggregationTest.java @@ -22,6 +22,8 @@ import org.gradoop.common.model.impl.properties.PropertyValue; import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.flink.model.api.epgm.GraphCollection; +import org.gradoop.flink.model.impl.operators.aggregation.functions.containment.HasEdgeLabel; +import org.gradoop.flink.model.impl.operators.aggregation.functions.containment.HasVertexLabel; import org.gradoop.flink.model.impl.operators.aggregation.functions.count.EdgeCount; import org.gradoop.flink.model.impl.operators.aggregation.functions.count.VertexCount; import org.gradoop.flink.model.impl.operators.aggregation.functions.max.MaxEdgeProperty; @@ -40,6 +42,7 @@ import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public abstract class ApplyAggregationTest extends AggregationTest { @@ -362,4 +365,60 @@ public void testCollectionVertexAndEdgeCount() throws Exception { assertTrue("wrong number of output graph heads", graphHeadCount == 4); } + + @Test + public void testCollectionHasVertexAndEdgeLabelTrue() throws Exception { + GraphCollection collection = getSocialNetworkLoader() + .getGraphCollectionByVariables("g0", "g1", "g2", "g3"); + + HasVertexLabel hasPerson = new HasVertexLabel("Person"); + HasEdgeLabel hasKnows = new HasEdgeLabel("knows"); + + collection = collection + .apply(new ApplyAggregation(hasKnows)) + .apply(new ApplyAggregation(hasPerson)); + + List graphHeads = collection.getGraphHeads().collect(); + + for (EPGMGraphHead graphHead : graphHeads) { + // check vertex label + assertTrue("Property hasVertexLabel_Person not set", + graphHead.hasProperty(hasPerson.getAggregatePropertyKey())); + assertTrue("Property hasVertexLabel_Person is false, should be true", + graphHead.getPropertyValue(hasPerson.getAggregatePropertyKey()).getBoolean()); + // check edge label + assertTrue("Property hasEdgeLabel_knows not set", + graphHead.hasProperty(hasKnows.getAggregatePropertyKey())); + assertTrue("Property hasEdgeLabel_knows is false, should be true", + graphHead.getPropertyValue(hasKnows.getAggregatePropertyKey()).getBoolean()); + } + } + + @Test + public void testCollectionHasVertexAndEdgeLabelFalse() throws Exception { + GraphCollection collection = getSocialNetworkLoader() + .getGraphCollectionByVariables("g0", "g1", "g2", "g3"); + + HasVertexLabel hasSomeLabel = new HasVertexLabel("someLabel"); + HasEdgeLabel hasOtherLabel = new HasEdgeLabel("otherLabel"); + + collection = collection + .apply(new ApplyAggregation(hasSomeLabel)) + .apply(new ApplyAggregation(hasOtherLabel)); + + List graphHeads = collection.getGraphHeads().collect(); + + for (EPGMGraphHead graphHead : graphHeads) { + // check edge label + assertTrue("Property hasEdgeLabel_otherLabel not set", + graphHead.hasProperty(hasOtherLabel.getAggregatePropertyKey())); + assertFalse("Property hasEdgeLabel_otherLabel is true, should be false", + graphHead.getPropertyValue(hasOtherLabel.getAggregatePropertyKey()).getBoolean()); + // check vertex label + assertTrue("Property hasVertexLabel_someLabel not set", + graphHead.hasProperty(hasSomeLabel.getAggregatePropertyKey())); + assertFalse("Property hasVertexLabel_someLabel is true, should be false", + graphHead.getPropertyValue(hasSomeLabel.getAggregatePropertyKey()).getBoolean()); + } + } } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/drilling/DrillTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/drilling/DrillTest.java index c8298028bcc2..7df7b8f01449 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/drilling/DrillTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/drilling/DrillTest.java @@ -26,40 +26,40 @@ public class DrillTest extends GradoopFlinkTestBase { //---------------------------------------------------------------------------- - // Tests for drill up + // Tests for roll up //---------------------------------------------------------------------------- - @Test(expected = NullPointerException.class) - public void testVertexDrillUpNoProperty() { + @SuppressWarnings("unused") + @Test(expected = NullPointerException.class) + public void testVertexRollUpNoProperty() { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); LogicalGraph output = input.callForGraph(new Drill.DrillBuilder() - .drillVertex(true) - .buildDrillUp()); + .buildRollUp()); } - @Test(expected = NullPointerException.class) - public void testVertexDrillUpFunctionOnly() { + @SuppressWarnings("unused") + @Test(expected = NullPointerException.class) + public void testVertexRollUpFunctionOnly() { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); LogicalGraph output = input .callForGraph(new Drill.DrillBuilder() - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()); + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()); } @Test - public void testVertexDrillUpPropertyKeyFunction() throws Exception { + public void testVertexRollUpPropertyKeyFunction() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); - + loader.appendToDatabaseFromString("expected[" + "(v00:Forum {topic : \"rdf\",memberCount : 1563145L,memberCount__1 : 1563145521L})" + "(v01:Forum {topic : \"graph\",memberCount: 451341L,memberCount__1: 451341564L})" + @@ -80,14 +80,14 @@ public void testVertexDrillUpPropertyKeyFunction() throws Exception { "]"); LogicalGraph output = input - .drillUpVertex("memberCount", new DrillDivideBy(1000L)); + .rollUpVertex("memberCount", new DrillDivideBy(1000L)); collectAndAssertTrue( output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); } @Test - public void testVertexDrillUpPropertyKeyFunctionNewPropertyKey() throws Exception { + public void testVertexRollUpPropertyKeyFunctionNewPropertyKey() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -115,9 +115,8 @@ public void testVertexDrillUpPropertyKeyFunctionNewPropertyKey() throws Exceptio .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount") .setNewPropertyKey("memberCount_in_K") - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()); + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()); collectAndAssertTrue( @@ -125,7 +124,7 @@ public void testVertexDrillUpPropertyKeyFunctionNewPropertyKey() throws Exceptio } @Test - public void testVertexDrillUpChainedDrillUp() throws Exception { + public void testVertexRollUpChainedRollUp() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -152,15 +151,15 @@ public void testVertexDrillUpChainedDrillUp() throws Exception { "]"); LogicalGraph output = input - .drillUpVertex("memberCount", new DrillDivideBy(1000L)) - .drillUpVertex("memberCount", new DrillDivideBy(1000L)); + .rollUpVertex("memberCount", new DrillDivideBy(1000L)) + .rollUpVertex("memberCount", new DrillDivideBy(1000L)); collectAndAssertTrue( output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); } @Test - public void testVertexDrillUpNewPropertyKeyChainedDrillUp() throws Exception { + public void testVertexRollUpNewPropertyKeyChainedRollUp() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -190,22 +189,20 @@ public void testVertexDrillUpNewPropertyKeyChainedDrillUp() throws Exception { .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount") .setNewPropertyKey("memberCount_in_K") - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()) + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount_in_K") .setNewPropertyKey("memberCount_in_M") - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()); + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()); collectAndAssertTrue( output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); } @Test - public void testVertexDrillUpMixedChainedDrillUp() throws Exception { + public void testVertexRollUpMixedChainedRollUp() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -237,25 +234,21 @@ public void testVertexDrillUpMixedChainedDrillUp() throws Exception { .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birthMillis") .setNewPropertyKey("birth") - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()) + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birth") - .setFunction(new DrillDivideBy(60L)) - .drillVertex(true) - .buildDrillUp()) + .setVertexDrillFunction(new DrillDivideBy(60L)) + .buildRollUp()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birth") - .setFunction(new DrillDivideBy(60L)) - .drillVertex(true) - .buildDrillUp()) + .setVertexDrillFunction(new DrillDivideBy(60L)) + .buildRollUp()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birth") .setNewPropertyKey("birthDays") - .setFunction(new DrillDivideBy(24L)) - .drillVertex(true) - .buildDrillUp()); + .setVertexDrillFunction(new DrillDivideBy(24L)) + .buildRollUp()); collectAndAssertTrue( output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); @@ -264,7 +257,7 @@ public void testVertexDrillUpMixedChainedDrillUp() throws Exception { @Test - public void testEdgeDrillUpPropertyKeyFunction() throws Exception { + public void testEdgeRollUpPropertyKeyFunction() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -289,26 +282,95 @@ public void testEdgeDrillUpPropertyKeyFunction() throws Exception { "]"); LogicalGraph output = input - .drillUpEdge("until", new DrillDivideBy(1000L)); + .rollUpEdge("until", new DrillDivideBy(1000L)); + + collectAndAssertTrue( + output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); + } + + @Test + public void testEdgeRollUpUsingDrillBuilder() throws Exception { + FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); + + LogicalGraph input = loader.getLogicalGraphByVariable("input"); + loader.appendToDatabaseFromString("expected[" + + "(v00:Forum {topic : \"rdf\",memberCount : 1563145521L})" + + "(v01:Forum {topic : \"graph\",memberCount: 451341564L})" + + "(v02:User {gender : \"male\",birthMillis : 500000000000L})" + + "(v03:User {gender : \"male\",birthMillis : 530000000000L})" + + "(v04:User {gender : \"male\",birthMillis : 560000000000L})" + + "(v05:User {gender : \"female\",birthMillis : 590000000000L})" + + "(v02)-[:member {until : 1550000000L,until__1 : 1550000000000L}]->(v00)" + + "(v03)-[:member {until : 1550000000L,until__1 : 1550000000000L}]->(v00)" + + "(v03)-[:member {until : 1550000000L,until__1 : 1550000000000L}]->(v01)" + + "(v04)-[:member {until : 1550000000L,until__1 : 1550000000000L}]->(v01)" + + "(v05)-[:member {until : 1550000000L,until__1 : 1550000000000L}]->(v01)" + + "(v02)-[:knows {since : 1350000000000L}]->(v03)" + + "(v03)-[:knows {since : 1350000000000L}]->(v02)" + + "(v03)-[:knows {since : 1350000000000L}]->(v04)" + + "(v03)-[:knows {since : 1350000000000L}]->(v05)" + + "(v05)-[:knows {since : 1350000000000L}]->(v04)" + + "]"); + + LogicalGraph output = input.callForGraph(new Drill.DrillBuilder() + .setPropertyKey("until") + .setEdgeDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()); + collectAndAssertTrue( output.equalsByElementData(loader.getLogicalGraphByVariable("expected"))); } + @Test + public void testGraphHeadRollUpUsingDrillBuilder() throws Exception { + FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); + LogicalGraph input = loader.getLogicalGraphByVariable("input"); + + loader.appendToDatabaseFromString( + "expected{title : \"Graph\", globalMemberCount : 42L,globalMemberCount__1: 42000L}[" + + "(v0:Forum {topic : \"rdf\",memberCount : 1563145521L})" + + "(v1:Forum {topic : \"graph\",memberCount: 451341564L})" + + "(v2:User {gender : \"male\",birthMillis : 500000000000L})" + + "(v3:User {gender : \"male\",birthMillis : 530000000000L})" + + "(v4:User {gender : \"male\",birthMillis : 560000000000L})" + + "(v5:User {gender : \"female\",birthMillis : 590000000000L})" + + "(v2)-[:member {until : 1550000000000L}]->(v0)" + + "(v3)-[:member {until : 1550000000000L}]->(v0)" + + "(v3)-[:member {until : 1550000000000L}]->(v1)" + + "(v4)-[:member {until : 1550000000000L}]->(v1)" + + "(v5)-[:member {until : 1550000000000L}]->(v1)" + + "(v2)-[:knows {since : 1350000000000L}]->(v3)" + + "(v3)-[:knows {since : 1350000000000L}]->(v2)" + + "(v3)-[:knows {since : 1350000000000L}]->(v4)" + + "(v3)-[:knows {since : 1350000000000L}]->(v5)" + + "(v5)-[:knows {since : 1350000000000L}]->(v4)" + + "]"); + + LogicalGraph expected = loader.getLogicalGraphByVariable("expected"); + + LogicalGraph result = input.callForGraph(new Drill.DrillBuilder() + .setPropertyKey("globalMemberCount") + .setGraphheadDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()); + + collectAndAssertTrue(result.equalsByData(expected)); + } + //---------------------------------------------------------------------------- // Tests for drill down //---------------------------------------------------------------------------- - @Test(expected = NullPointerException.class) + @SuppressWarnings("unused") + @Test(expected = NullPointerException.class) public void testVertexDrillDownNoProperty() { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); LogicalGraph output = input.callForGraph(new Drill.DrillBuilder() - .drillVertex(true) .buildDrillDown()); } @@ -373,8 +435,7 @@ public void testVertexDrillDownPropertyKeyFunctionNewPropertyKey() throws Except .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount") .setNewPropertyKey("memberCount_times_K") - .setFunction(new DrillMultiplyBy(1000L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(1000L)) .buildDrillDown()); @@ -444,14 +505,12 @@ public void testVertexDrillDownNewPropertyKeyChainedDrillDown() throws Exception .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount") .setNewPropertyKey("memberCount_times_K") - .setFunction(new DrillMultiplyBy(1000L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(1000L)) .buildDrillDown()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount_times_K") .setNewPropertyKey("memberCount_times_M") - .setFunction(new DrillMultiplyBy(1000L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(1000L)) .buildDrillDown()); collectAndAssertTrue( @@ -487,24 +546,20 @@ public void testVertexDrillDownMixedChainedDrillDown() throws Exception { .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birthMillis") .setNewPropertyKey("birthLowerMillis") - .setFunction(new DrillMultiplyBy(10L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(10L)) .buildDrillDown()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birthLowerMillis") - .setFunction(new DrillMultiplyBy(10L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(10L)) .buildDrillDown()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birthLowerMillis") - .setFunction(new DrillMultiplyBy(10L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(10L)) .buildDrillDown()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("birthLowerMillis") .setNewPropertyKey("birthTenNanos") - .setFunction(new DrillMultiplyBy(10L)) - .drillVertex(true) + .setVertexDrillFunction(new DrillMultiplyBy(10L)) .buildDrillDown()); collectAndAssertTrue( @@ -547,18 +602,18 @@ public void testEdgeDrillDownPropertyKeyFunction() throws Exception { //---------------------------------------------------------------------------- - // Tests for drill down after drill up + // Tests for drill down after roll up //---------------------------------------------------------------------------- @Test - public void testVertexDrillDownAfterDrillUp() throws Exception { + public void testVertexDrillDownAfterRollUp() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); LogicalGraph output = input - .drillUpVertex("memberCount", new DrillDivideBy(1000L)) + .rollUpVertex("memberCount", new DrillDivideBy(1000L)) .drillDownVertex("memberCount"); collectAndAssertTrue( @@ -566,7 +621,7 @@ public void testVertexDrillDownAfterDrillUp() throws Exception { } @Test - public void testVertexDrillDownAfterDrillUpNewPropertyKey() throws Exception { + public void testVertexDrillDownAfterRollUpNewPropertyKey() throws Exception { FlinkAsciiGraphLoader loader = getLoaderFromString(getDrillInput()); LogicalGraph input = loader.getLogicalGraphByVariable("input"); @@ -575,13 +630,11 @@ public void testVertexDrillDownAfterDrillUpNewPropertyKey() throws Exception { .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount") .setNewPropertyKey("memberCount_in_K") - .setFunction(new DrillDivideBy(1000L)) - .drillVertex(true) - .buildDrillUp()) + .setVertexDrillFunction(new DrillDivideBy(1000L)) + .buildRollUp()) .callForGraph(new Drill.DrillBuilder() .setPropertyKey("memberCount_in_K") .setNewPropertyKey("memberCount") - .drillVertex(true) .buildDrillDown()); collectAndAssertTrue( @@ -593,7 +646,7 @@ public void testVertexDrillDownAfterDrillUpNewPropertyKey() throws Exception { private String getDrillInput() { - return "input[" + + return "input{title : \"Graph\", globalMemberCount : 42000L}[" + "(v0:Forum {topic : \"rdf\",memberCount : 1563145521L})" + "(v1:Forum {topic : \"graph\",memberCount: 451341564L})" + "(v2:User {gender : \"male\",birthMillis : 500000000000L})" + diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/ParametrizedTestForGraphSampling.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/ParametrizedTestForGraphSampling.java index 90c9847fece8..3efd07d98653 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/ParametrizedTestForGraphSampling.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/ParametrizedTestForGraphSampling.java @@ -24,55 +24,200 @@ import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.operators.sampling.functions.Neighborhood; +import org.gradoop.flink.model.impl.operators.sampling.functions.VertexDegree; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +/** + * Parameterized test-class from which all sampling test-classes are derived. + * Derived test-classes need to define the parameters as {@code Iterable data()} + */ @RunWith(Parameterized.class) public abstract class ParametrizedTestForGraphSampling extends GradoopFlinkTestBase { + /** + * Name for test-case + */ + private String testName; + /** + * Seed-value for random number generator, e.g. 0L + */ + long seed; + /** + * Value for sample size, e.g. 0.5 + */ + float sampleSize; + /** + * Value for edge sample size (if sampled separately), e.g. 0.5 + */ + float edgeSampleSize; + /** + * The vertex neighborhood type. Distinguishes ingoing, outgoing edges or both. + */ + Neighborhood neighborType = Neighborhood.BOTH; + /** + * The dampening factor used by Flinks PageRank-algorithm + */ + double dampeningFactor = 0.5; + /** + * The iteration number used by Flinks PageRank-algorithm + */ + int maxIteration = 20; + /** + * Whether to sample vertices with scaled PageRank-score + * greater (true) or equal/smaller (false) the sampleSize + */ + boolean sampleGreaterThanThreshold = true; + /** + * The vertex degree type. Distinguishes in-degree, out-degree or the sum of both. + */ + VertexDegree degreeType = VertexDegree.BOTH; + /** + * The threshold for the vertex degree + */ + long degreeThreshold = 3L; + /** + * Sampling type for VertexEdgeSampling + */ + RandomVertexEdgeSampling.VertexEdgeSamplingType vertexEdgeSamplingType = + RandomVertexEdgeSampling.VertexEdgeSamplingType.SimpleVersion; + + /** + * List of original vertices + */ + List dbVertices; + /** + * List of original edges + */ + List dbEdges; + /** + * List of sampled vertices + */ + List newVertices; + /** + * IDs from sampled vertices + */ + Set newVertexIDs; + /** + * List of sampled edges + */ + List newEdges; + + /** + * Common Constructor for most samplings + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + */ + public ParametrizedTestForGraphSampling(String testName, long seed, float sampleSize) { + this.testName = testName; + this.seed = seed; + this.sampleSize = sampleSize; + } - private final String testName; - - protected final long seed; - - protected final float sampleSize; + /** + * Constructor for VertexNeighborhoodSamplingTest + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + * @param neighborType The vertex neighborhood type, e.g. Neighborhood.BOTH + */ + public ParametrizedTestForGraphSampling(String testName, long seed, float sampleSize, + Neighborhood neighborType) { + this(testName, seed, sampleSize); + this.neighborType = neighborType; + } - protected final Neighborhood.NeighborType neighborType; + /** + * Constructor for PageRankSamplingTest + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + * @param dampeningFactor The dampening factor used by Flinks PageRank-algorithm, e.g. 0.85 + * @param maxIteration The iteration number used by Flinks PageRank-algorithm, e.g. 20 + */ + public ParametrizedTestForGraphSampling(String testName, long seed, float sampleSize, + double dampeningFactor, int maxIteration, boolean sampleGreaterThanThreshold) { + this(testName, seed, sampleSize); + this.dampeningFactor = dampeningFactor; + this.maxIteration = maxIteration; + this.sampleGreaterThanThreshold = sampleGreaterThanThreshold; + } - public ParametrizedTestForGraphSampling(String testName, String seed, String sampleSize, - String neighborType) { - this.testName = testName; - this.seed = Long.parseLong(seed); - this.sampleSize = Float.parseFloat(sampleSize); - this.neighborType = Neighborhood.fromString(neighborType); + /** + * Constructor for LimitedDegreeVertexSamplingTest + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + * @param degreeType The vertex degree type, e.g. VertexDegree.BOTH + * @param degreeThreshold The threshold for the vertex degree, e.g. 3 + */ + public ParametrizedTestForGraphSampling(String testName, long seed, float sampleSize, + VertexDegree degreeType, long degreeThreshold) { + this(testName, seed, sampleSize); + this.degreeType = degreeType; + this.degreeThreshold = degreeThreshold; } - public abstract UnaryGraphToGraphOperator getSamplingOperator(); + /** + * Constructor for VertexEdgeSamplingTest + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for vertex sample size, e.g. 0.5 + * @param edgeSampleSize Value for edge sample size, e.g. 0.5 + * @param vertexEdgeSamplingType Type for VertexEdgeSampling, e.g. SimpleVersion + */ + public ParametrizedTestForGraphSampling(String testName, long seed, float sampleSize, + float edgeSampleSize, RandomVertexEdgeSampling.VertexEdgeSamplingType vertexEdgeSamplingType) { + this(testName, seed, sampleSize); + this.edgeSampleSize = edgeSampleSize; + this.vertexEdgeSamplingType = vertexEdgeSamplingType; + } + /** + * Gets the sampling operator used for testing. + * + * @return The sampling operator + */ + public abstract SamplingAlgorithm getSamplingOperator(); + + /** + * Common test-case. + * + * @throws Exception Exception thrown by graph loading + */ @Test - public void randomSamplingTest() throws Exception { + public void samplingTest() throws Exception { LogicalGraph dbGraph = getSocialNetworkLoader().getDatabase().getDatabaseGraph(); + LogicalGraph newGraph = getSamplingOperator().sample(dbGraph); - LogicalGraph newGraph = getSamplingOperator().execute(dbGraph); //dbGraph.sampleRandomNodes(0.272f); - - validateResult(dbGraph, newGraph); + validateGraph(dbGraph, newGraph); + validateSpecific(dbGraph, newGraph); } - private void validateResult(LogicalGraph input, LogicalGraph output) - throws Exception { - List dbVertices = Lists.newArrayList(); - List dbEdges = Lists.newArrayList(); - List newVertices = Lists.newArrayList(); - List newEdges = Lists.newArrayList(); + /** + * The common graph validation used by all graph samplings + * + * @param input The input graph + * @param output The sampled graph + */ + private void validateGraph(LogicalGraph input, LogicalGraph output) throws Exception { + dbVertices = Lists.newArrayList(); + dbEdges = Lists.newArrayList(); + newVertices = Lists.newArrayList(); + newEdges = Lists.newArrayList(); input.getVertices().output(new LocalCollectionOutputFormat<>(dbVertices)); input.getEdges().output(new LocalCollectionOutputFormat<>(dbEdges)); @@ -84,50 +229,26 @@ private void validateResult(LogicalGraph input, LogicalGraph output) assertNotNull("graph was null", output); - Set newVertexIDs = new HashSet<>(); + newVertexIDs = new HashSet<>(); for (Vertex vertex : newVertices) { - assertTrue(dbVertices.contains(vertex)); + assertTrue("sampled vertex is not part of the original graph", dbVertices.contains(vertex)); newVertexIDs.add(vertex.getId()); } for (Edge edge : newEdges) { - assertTrue(dbEdges.contains(edge)); - assertTrue(newVertexIDs.contains(edge.getSourceId())); - assertTrue(newVertexIDs.contains(edge.getTargetId())); - } - dbEdges.removeAll(newEdges); - for (Edge edge : dbEdges) { - assertFalse( - newVertexIDs.contains(edge.getSourceId()) && - newVertexIDs.contains(edge.getTargetId())); + assertTrue("sampled edge is not part of the original graph", dbEdges.contains(edge)); + assertTrue("sampled edge has source vertex which is not part of the sampled graph", + newVertexIDs.contains(edge.getSourceId())); + assertTrue("sampled edge has target vertex which is not part of the sampled graph", + newVertexIDs.contains(edge.getTargetId())); } } - @Parameterized.Parameters(name = "{index}: {0}") - public static Iterable data() { - return Arrays.asList( - new String[] { - "With seed and both neighborhood", - "-4181668494294894490", - "0.272f", - "Both" - }, - new String[] { - "Without seed and both neighborhood", - "-4181668494294894490", - "0", - "Both" - }, - new String[] { - "With seed and input neighborhood", - "-4181668494294894490", - "0.272f", - "Input" - }, - new String[] { - "With seed and output neighborhood", - "-4181668494294894490", - "0.272f", - "Output" - }); - } + /** + * The specific graph validation used by some graph samplings. + * Needs to be implemented in the respective sampling test-class. + * + * @param input The input graph + * @param output The sampled graph + */ + public abstract void validateSpecific(LogicalGraph input, LogicalGraph output); } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSamplingTest.java index 14ea57b26596..dad57c70f477 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomEdgeSamplingTest.java @@ -15,85 +15,70 @@ */ package org.gradoop.flink.model.impl.operators.sampling; -import com.google.common.collect.Lists; -import org.apache.flink.api.java.io.LocalCollectionOutputFormat; import org.gradoop.common.model.impl.id.GradoopId; import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.flink.model.GradoopFlinkTestBase; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.junit.Test; +import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.junit.runners.Parameterized; +import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; -public class RandomEdgeSamplingTest extends GradoopFlinkTestBase { +public class RandomEdgeSamplingTest extends ParametrizedTestForGraphSampling { - @Test - public void randomEdgeSamplingTest() throws Exception { - LogicalGraph dbGraph = getSocialNetworkLoader() - .getDatabase().getDatabaseGraph(); - - LogicalGraph newGraph = new RandomEdgeSampling(0.272f).execute(dbGraph); - - validateResult(dbGraph, newGraph); + /** + * Creates a new RandomEdgeSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + */ + public RandomEdgeSamplingTest(String testName, String seed, String sampleSize) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize)); } - @Test - public void randomEdgeSamplingTestWithSeed() throws Exception { - LogicalGraph dbGraph = getSocialNetworkLoader() - .getDatabase().getDatabaseGraph(); - - LogicalGraph newGraph = - new RandomEdgeSampling(0.272f, -4181668494294894490L) - .execute(dbGraph); - - validateResult(dbGraph, newGraph); + /** + * {@inheritDoc} + */ + @Override + public SamplingAlgorithm getSamplingOperator() { + return new RandomEdgeSampling(sampleSize, seed); } - private void validateResult(LogicalGraph input, LogicalGraph output) - throws Exception { - List dbVertices = Lists.newArrayList(); - List dbEdges = Lists.newArrayList(); - List newVertices = Lists.newArrayList(); - List newEdges = Lists.newArrayList(); - - input.getVertices().output(new LocalCollectionOutputFormat<>(dbVertices)); - input.getEdges().output(new LocalCollectionOutputFormat<>(dbEdges)); - - output.getVertices().output(new LocalCollectionOutputFormat<>(newVertices)); - output.getEdges().output(new LocalCollectionOutputFormat<>(newEdges)); - - getExecutionEnvironment().execute(); - - // Test, if there is a result graph - assertNotNull("graph was null", output); - - Set newVertexIDs = new HashSet<>(); - for (Vertex vertex : newVertices) { - // Test, if all new vertices are taken from the original graph - assertTrue("sampled vertex is not part of the original graph", dbVertices.contains(vertex)); - newVertexIDs.add(vertex.getId()); - } - + /** + * {@inheritDoc} + */ + @Override + public void validateSpecific(LogicalGraph input, LogicalGraph output) { Set connectedVerticesIDs = new HashSet<>(); for (Edge edge : newEdges) { - // Test, if all new edges are taken from the original graph - assertTrue("sampled edge is not part of the original graph", dbEdges.contains(edge)); - // Test, if all source- and target-vertices from new edges are part of the sampled graph, too - assertTrue("sampled edge has source vertex which is not part of the sampled graph", - newVertexIDs.contains(edge.getSourceId())); connectedVerticesIDs.add(edge.getSourceId()); - assertTrue("sampled edge has target vertex which is not part of the sampled graph", - newVertexIDs.contains(edge.getTargetId())); connectedVerticesIDs.add(edge.getTargetId()); } - - // Test, if there aren't any unconnected vertices left newVertexIDs.removeAll(connectedVerticesIDs); assertTrue("there are unconnected vertices in the sampled graph", newVertexIDs.isEmpty()); } + + /** + * Parameters called when running the test + * + * @return List of parameters + */ + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() { + return Arrays.asList( + new String[] { + "EdgeSamplingTest with seed", + "-4181668494294894490", + "0.272f" + }, + new String[] { + "EdgeSamplingTest without seed", + "0", + "0.272f" + }); + } } \ No newline at end of file diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSamplingTest.java index 61f93853c4ea..200818a03db4 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomLimitedDegreeVertexSamplingTest.java @@ -17,123 +17,88 @@ import com.google.common.collect.Lists; import org.apache.flink.api.java.io.LocalCollectionOutputFormat; -import org.gradoop.common.model.impl.id.GradoopId; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.algorithms.gelly.vertexdegrees.DistinctVertexDegrees; -import org.gradoop.flink.model.GradoopFlinkTestBase; import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; import org.gradoop.flink.model.impl.operators.sampling.functions.VertexDegree; -import org.junit.Test; -import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import static org.junit.Assert.*; - -@RunWith(Parameterized.class) -public class RandomLimitedDegreeVertexSamplingTest extends GradoopFlinkTestBase { - - private final String testName; - - private final long randomSeed; - - private final float sampleSize; - - private final VertexDegree degreeType; - - private final long degreeThreshold; - - private final String degreePropertyName; - - public RandomLimitedDegreeVertexSamplingTest(String testName, String randomSeed, - String sampleSize, String degreeType, String degreeThreshold) { - this.testName = testName; - this.randomSeed = Long.parseLong(randomSeed); - this.sampleSize = Float.parseFloat(sampleSize); - this.degreeType = VertexDegree.valueOf(degreeType); - this.degreeThreshold = Long.parseLong(degreeThreshold); - this.degreePropertyName = this.degreeType.getName(); +import static org.junit.Assert.assertFalse; + +public class RandomLimitedDegreeVertexSamplingTest extends ParametrizedTestForGraphSampling { + + /** + * Creates a new RandomLimitedDegreeVertexSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + * @param degreeType The vertex degree type, e.g. VertexDegree.BOTH + * @param degreeThreshold The threshold for the vertex degree, e.g. 3 + */ + public RandomLimitedDegreeVertexSamplingTest(String testName, String seed, String sampleSize, + String degreeType, String degreeThreshold) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize), + VertexDegree.valueOf(degreeType), Long.parseLong(degreeThreshold)); } - @Test - public void randomLimitedDegreeVertexSamplingTest() throws Exception { - LogicalGraph dbGraph = getSocialNetworkLoader() - .getDatabase().getDatabaseGraph(); - - LogicalGraph newGraph = new RandomLimitedDegreeVertexSampling(sampleSize, randomSeed, - degreeThreshold, degreeType).execute(dbGraph); - - validateResult(dbGraph, newGraph); + /** + * {@inheritDoc} + */ + @Override + public SamplingAlgorithm getSamplingOperator() { + return new RandomLimitedDegreeVertexSampling(sampleSize, seed, degreeThreshold, degreeType); } - private void validateResult(LogicalGraph input, LogicalGraph output) - throws Exception { - List dbVertices = Lists.newArrayList(); - List dbEdges = Lists.newArrayList(); - List newVertices = Lists.newArrayList(); - List newEdges = Lists.newArrayList(); - - LogicalGraph inputWithDegrees = new DistinctVertexDegrees(VertexDegree.IN_OUT.getName(), - VertexDegree.IN.getName(),VertexDegree.OUT.getName(),true).execute(input); - - inputWithDegrees.getVertices().output(new LocalCollectionOutputFormat<>(dbVertices)); - inputWithDegrees.getEdges().output(new LocalCollectionOutputFormat<>(dbEdges)); - - output.getVertices().output(new LocalCollectionOutputFormat<>(newVertices)); - output.getEdges().output(new LocalCollectionOutputFormat<>(newEdges)); - - getExecutionEnvironment().execute(); - - // Test, if there is a result graph - assertNotNull("graph was null", output); - - Set newVertexIDs = new HashSet<>(); - for (Vertex vertex : newVertices) { - // Test, if all new vertices are taken from the original graph - assertTrue("sampled vertex is not part of the original graph", - dbVertices.contains(vertex)); - newVertexIDs.add(vertex.getId()); - } - - for (Edge edge : newEdges) { - // Test, if all new edges are taken from the original graph - assertTrue("sampled edge is not part of the original graph", dbEdges.contains(edge)); - // Test, if all source- and target-vertices from new edges are part of the sampled graph, too - assertTrue("sampled edge has source vertex which is not part of the sampled graph", - newVertexIDs.contains(edge.getSourceId())); - assertTrue("sampled edge has target vertex which is not part of the sampled graph", - newVertexIDs.contains(edge.getTargetId())); + /** + * {@inheritDoc} + */ + @Override + public void validateSpecific(LogicalGraph input, LogicalGraph output) { + List dbDegreeVertices = Lists.newArrayList(); + LogicalGraph inputWithDegrees = new DistinctVertexDegrees( + VertexDegree.BOTH.getName(), + VertexDegree.IN.getName(), + VertexDegree.OUT.getName(), + true).execute(input); + inputWithDegrees.getVertices().output(new LocalCollectionOutputFormat<>(dbDegreeVertices)); + + try { + getExecutionEnvironment().execute(); + } catch (Exception e) { + e.printStackTrace(); } - // Test, if there aren't any source- and target-vertices from not sampled edges left dbEdges.removeAll(newEdges); for (Edge edge : dbEdges) { assertFalse("there are vertices from edges, which are not part of the sampled graph", - newVertexIDs.contains(edge.getSourceId()) && - newVertexIDs.contains(edge.getTargetId())); + newVertexIDs.contains(edge.getSourceId()) && newVertexIDs.contains(edge.getTargetId())); } - // Test, if all vertices with degree higher the given threshold were sampled List verticesSampledByDegree = Lists.newArrayList(); - for (Vertex vertex : dbVertices) { - if ((Long.parseLong(vertex.getPropertyValue(degreePropertyName).toString()) - > degreeThreshold) && newVertices.contains(vertex)) { + for (Vertex vertex : dbDegreeVertices) { + if ((Long.parseLong(vertex.getPropertyValue(degreeType.getName()).toString()) > degreeThreshold) && + newVertices.contains(vertex)) { verticesSampledByDegree.add(vertex); } } - dbVertices.removeAll(verticesSampledByDegree); - for (Vertex vertex : dbVertices) { - assertFalse("vertex with degree higher than degree threshold was not sampled", - Long.parseLong(vertex.getPropertyValue(degreePropertyName).toString()) - > degreeThreshold); + dbDegreeVertices.removeAll(verticesSampledByDegree); + for (Vertex vertex : dbDegreeVertices) { + assertFalse("vertex with degree greater than degree threshold was not sampled", + Long.parseLong(vertex.getPropertyValue(degreeType.getName()).toString()) > degreeThreshold); } } + /** + * Parameters called when running the test + * + * @return List of parameters + */ @Parameterized.Parameters(name = "{index}: {0}") public static Iterable data() { return Arrays.asList( @@ -141,14 +106,14 @@ public static Iterable data() { "With seed and the sum of in- and out-degree with value = 3", "-4181668494294894490", "0.272f", - "IN_OUT", + "BOTH", "3" }, new String[] { "Without seed and the sum of in- and out-degree with value = 3", "0", "0.272f", - "IN_OUT", + "BOTH", "3" }, new String[] { diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSamplingTest.java index 4bca01884fd7..ac6d6bf77d1a 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomNonUniformVertexSamplingTest.java @@ -15,17 +15,66 @@ */ package org.gradoop.flink.model.impl.operators.sampling; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; public class RandomNonUniformVertexSamplingTest extends ParametrizedTestForGraphSampling { - public RandomNonUniformVertexSamplingTest(String testName, String seed, String sampleSize, - String neighborType) { - super(testName, seed, sampleSize, neighborType); + /** + * Creates a new RandomNonUniformVertexSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + */ + public RandomNonUniformVertexSamplingTest(String testName, String seed, String sampleSize) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize)); + } + + /** + * {@inheritDoc} + */ + @Override + public SamplingAlgorithm getSamplingOperator() { + return new RandomNonUniformVertexSampling(sampleSize, seed); } + /** + * {@inheritDoc} + */ @Override - public UnaryGraphToGraphOperator getSamplingOperator() { - return new RandomNonUniformVertexSampling(sampleSize,seed); + public void validateSpecific(LogicalGraph input, LogicalGraph output) { + + dbEdges.removeAll(newEdges); + for (Edge edge : dbEdges) { + assertFalse("there are vertices from edges, which are not part of the sampled graph", + newVertexIDs.contains(edge.getSourceId()) && newVertexIDs.contains(edge.getTargetId())); + } + } + + /** + * Parameters called when running the test + * + * @return List of parameters + */ + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() { + return Arrays.asList( + new String[] { + "NonUniformVertexSamplingTest with seed", + "-4181668494294894490", + "0.272f" + }, + new String[] { + "NonUniformVertexSamplingTest without seed", + "0", + "0.272f" + }); } } \ No newline at end of file diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSamplingTest.java index a3606a768ef3..2ea868be2e32 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexEdgeSamplingTest.java @@ -15,16 +15,78 @@ */ package org.gradoop.flink.model.impl.operators.sampling; +import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.junit.runners.Parameterized; + +import java.util.Arrays; public class RandomVertexEdgeSamplingTest extends ParametrizedTestForGraphSampling { + + /** + * Creates a new RandomVertexEdgeSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for vertex sample size, e.g. 0.5 + * @param edgeSampleSize Value for edge sample size, e.g. 0.5 + * @param vertexEdgeSamplingType Type for VertexEdgeSampling, e.g. SimpleVersion + */ public RandomVertexEdgeSamplingTest(String testName, String seed, String sampleSize, - String neighborType) { - super(testName, seed, sampleSize, neighborType); + String edgeSampleSize, String vertexEdgeSamplingType) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize), Float.parseFloat(edgeSampleSize), + RandomVertexEdgeSampling.VertexEdgeSamplingType.valueOf(vertexEdgeSamplingType)); + } + + /** + * {@inheritDoc} + */ + @Override + public SamplingAlgorithm getSamplingOperator() { + return new RandomVertexEdgeSampling(sampleSize, edgeSampleSize, seed, vertexEdgeSamplingType); } + /** + * {@inheritDoc} + */ @Override - public UnaryGraphToGraphOperator getSamplingOperator() { - return new RandomVertexSampling(sampleSize, seed); + public void validateSpecific(LogicalGraph input, LogicalGraph output) {} + + /** + * Parameters called when running the test + * + * @return List of parameters + */ + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() { + return Arrays.asList( + new String[] { + "VertexEdgeSamplingTest with seed and simple version", + "-4181668494294894490", + "0.272f", + "0.272f", + "SimpleVersion" + }, + new String[] { + "VertexEdgeSamplingTest without seed and simple version", + "0", + "0.272f", + "0.272f", + "SimpleVersion" + }, + new String[] { + "VertexEdgeSamplingTest without seed and nonuniform version", + "0", + "0.272f", + "0.272f", + "NonuniformVersion" + }, + new String[] { + "VertexEdgeSamplingTest without seed and nonuniform hybrid version", + "0", + "0.272f", + "0.272f", + "NonuniformHybridVersion" + }); } } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSamplingTest.java index 587eac13fae0..e556796e551c 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexNeighborhoodSamplingTest.java @@ -15,18 +15,84 @@ */ package org.gradoop.flink.model.impl.operators.sampling; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.gradoop.flink.model.impl.operators.sampling.functions.Neighborhood; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; public class RandomVertexNeighborhoodSamplingTest extends ParametrizedTestForGraphSampling { + /** + * Creates a new RandomVertexNeighborhoodSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + * @param neighborType The vertex neighborhood type, e.g. Neighborhood.BOTH + */ public RandomVertexNeighborhoodSamplingTest(String testName, String seed, String sampleSize, - String neighborType) { - super(testName, seed, sampleSize, neighborType); + String neighborType) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize), + Neighborhood.valueOf(neighborType)); } + /** + * {@inheritDoc} + */ @Override - public UnaryGraphToGraphOperator getSamplingOperator() { + public SamplingAlgorithm getSamplingOperator() { return new RandomVertexNeighborhoodSampling(sampleSize, seed, neighborType); } + /** + * {@inheritDoc} + */ + @Override + public void validateSpecific(LogicalGraph input, LogicalGraph output) { + + dbEdges.removeAll(newEdges); + for (Edge edge : dbEdges) { + assertFalse("there are vertices from edges, which are not part of the sampled graph", + newVertexIDs.contains(edge.getSourceId()) && newVertexIDs.contains(edge.getTargetId())); + } + } + + /** + * Parameters called when running the test + * + * @return List of parameters + */ + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() { + return Arrays.asList( + new String[] { + "VertexNeighborhoodSamplingTest with seed and both neighborhood", + "-4181668494294894490", + "0.272f", + "BOTH" + }, + new String[] { + "VertexNeighborhoodSamplingTest without seed and both neighborhood", + "0", + "0.272f", + "BOTH" + }, + new String[] { + "VertexNeighborhoodSamplingTest with seed and input neighborhood", + "-4181668494294894490", + "0.272f", + "IN" + }, + new String[] { + "VertexNeighborhoodSamplingTest with seed and output neighborhood", + "-4181668494294894490", + "0.272f", + "OUT" + }); + } } \ No newline at end of file diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSamplingTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSamplingTest.java index c373fb5527df..ffa277cbc777 100644 --- a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSamplingTest.java +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/RandomVertexSamplingTest.java @@ -15,16 +15,66 @@ */ package org.gradoop.flink.model.impl.operators.sampling; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.api.operators.UnaryGraphToGraphOperator; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; public class RandomVertexSamplingTest extends ParametrizedTestForGraphSampling { - public RandomVertexSamplingTest(String testName, String seed, String sampleSize, - String neighborType) { - super(testName, seed, sampleSize, neighborType); + + /** + * Creates a new RandomVertexSamplingTest instance. + * + * @param testName Name for test-case + * @param seed Seed-value for random number generator, e.g. 0 + * @param sampleSize Value for sample size, e.g. 0.5 + */ + public RandomVertexSamplingTest(String testName, String seed, String sampleSize) { + super(testName, Long.parseLong(seed), Float.parseFloat(sampleSize)); } + /** + * {@inheritDoc} + */ @Override - public UnaryGraphToGraphOperator getSamplingOperator() { - return new RandomVertexSampling(sampleSize,seed); + public SamplingAlgorithm getSamplingOperator() { + return new RandomVertexSampling(sampleSize, seed); + } + + /** + * {@inheritDoc} + */ + @Override + public void validateSpecific(LogicalGraph input, LogicalGraph output) { + + dbEdges.removeAll(newEdges); + for (Edge edge : dbEdges) { + assertFalse("there are vertices from edges, which are not part of the sampled graph", + newVertexIDs.contains(edge.getSourceId()) && newVertexIDs.contains(edge.getTargetId())); + } + } + + /** + * Parameters called when running the test + * + * @return List of parameters + */ + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() { + return Arrays.asList( + new String[] { + "VertexSamplingTest with seed", + "-4181668494294894490", + "0.272f" + }, + new String[] { + "VertexSamplingTest without seed", + "0", + "0.272f" + }); } } diff --git a/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensityTest.java b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensityTest.java new file mode 100644 index 000000000000..7d3a2b63a0f0 --- /dev/null +++ b/gradoop-flink/src/test/java/org/gradoop/flink/model/impl/operators/sampling/statistics/GraphDensityTest.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.flink.model.impl.operators.sampling.statistics; + +import org.gradoop.flink.model.GradoopFlinkTestBase; +import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * Test-class for graph density computation. + */ +public class GraphDensityTest extends GradoopFlinkTestBase { + + /** + * Tests the computation of graph density for a logical graph + * + * @throws Exception If loading of the example-graph fails + */ + @Test + public void testGraphDensity() throws Exception { + LogicalGraph graph = getSocialNetworkLoader().getDatabase().getDatabaseGraph(); + + double density = graph.callForGraph(new GraphDensity()) + .getGraphHead() + .collect() + .get(0) + .getPropertyValue(SamplingEvaluationConstants.PROPERTY_KEY_DENSITY).getDouble(); + + // density should not be 0 + assertTrue("Graph density is 0", density > 0.); + // density for social network graph should be (24 / 11 * 10) = 0.21818... + assertTrue("Computed graph density is incorrect", density == (24d / 110d)); + } +} diff --git a/gradoop-flink/src/test/resources/data/csv/expected/expected.gdl b/gradoop-flink/src/test/resources/data/csv/expected/expected.gdl index db5cad2c3937..7f23dea0a667 100644 --- a/gradoop-flink/src/test/resources/data/csv/expected/expected.gdl +++ b/gradoop-flink/src/test/resources/data/csv/expected/expected.gdl @@ -1,5 +1,5 @@ expected [ - (v0:A {a:"foo",b:42,c:13.37f})-[e0:a {a:1234,b:13.37f}]->(v1:A {a:"bar",b:23,c:19.84f}), + (v0:A {a:"foo",b:42,c:13.37f,d: NULL})-[e0:a {a:1234,b:13.37f}]->(v1:A {a:"bar",b:23,c:19.84f}), (v1)-[e1:a {a:5678,b:23.42f}]->(v0), (v1)-[e2:b {a:3141L}]->(v2:B {a:1234L,b:true,c:0.123d}), (v2)-[e3:b {a:2718L}]->(v3:B {a:5678L,b:false,c:4.123d}), diff --git a/gradoop-flink/src/test/resources/data/csv/input/metadata.csv b/gradoop-flink/src/test/resources/data/csv/input/metadata.csv index 89a54fcbb6c9..443bcc3d91c8 100644 --- a/gradoop-flink/src/test/resources/data/csv/input/metadata.csv +++ b/gradoop-flink/src/test/resources/data/csv/input/metadata.csv @@ -1,4 +1,4 @@ -v;A;a:string,b:int,c:float +v;A;a:string,b:int,c:float,d:null v;B;a:long,b:boolean,c:double e;a;a:int,b:float e;b;a:long \ No newline at end of file diff --git a/gradoop-flink/src/test/resources/data/csv/input/vertices.csv b/gradoop-flink/src/test/resources/data/csv/input/vertices.csv index 1b966ee37360..726c239c105a 100644 --- a/gradoop-flink/src/test/resources/data/csv/input/vertices.csv +++ b/gradoop-flink/src/test/resources/data/csv/input/vertices.csv @@ -1,4 +1,4 @@ -000000000000000000000000;A;foo|42|13.37 +000000000000000000000000;A;foo|42|13.37|null 000000000000000000000001;A;bar|23|19.84 000000000000000000000002;B;1234|true|0.123 000000000000000000000003;B;5678|false|4.123 diff --git a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/edges.csv b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/edges.csv index 67b23b69bfd0..f2cb3fc8b798 100644 --- a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/edges.csv +++ b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/edges.csv @@ -1 +1 @@ -000000000000000000000002;000000000000000000000000;000000000000000000000001;creatorOf;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23 +000000000000000000000002;000000000000000000000000;000000000000000000000001;creatorOf;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23|null|[myString1, myString2]|[1234, 5678] diff --git a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/metadata.csv b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/metadata.csv index 5f93cafce12d..205f65f9c407 100644 --- a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/metadata.csv +++ b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/metadata.csv @@ -1,3 +1,3 @@ -v;User;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short -v;Post;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short -e;creatorOf;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short \ No newline at end of file +v;User;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short,keyf:null,keyg:set:string,keyh:set:int +v;Post;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short,keyf:null,keyg:set:string,keyh:set:int +e;creatorOf;key0:boolean,key1:int,key2:long,key3:float,key4:double,key5:string,key6:gradoopid,key7:localdate,key8:localtime,key9:localdatetime,keya:bigdecimal,keyb:map:string:double,keyc:list:string,keyd:list:int,keye:short,keyf:null,keyg:set:string,keyh:set:int \ No newline at end of file diff --git a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/vertices.csv b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/vertices.csv index c68ab83f69fd..22eba586d2c5 100644 --- a/gradoop-flink/src/test/resources/data/csv/input_extended_properties/vertices.csv +++ b/gradoop-flink/src/test/resources/data/csv/input_extended_properties/vertices.csv @@ -1,2 +1,2 @@ -000000000000000000000000;User;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23 -000000000000000000000001;Post;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23 +000000000000000000000000;User;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23|null|[myString1, myString2]|[1234, 5678] +000000000000000000000001;Post;true|23|23|2.3|2.3|23|000000000000000000000001|2018-06-01|18:06:01|2018-06-01T18:06:01|23|{myString1=12.345, myString2=67.89}|[myString1, myString2]|[1234, 5678]|23|null|[myString1, myString2]|[1234, 5678] diff --git a/gradoop-flink/src/test/resources/data/csv/input_indexed/metadata.csv b/gradoop-flink/src/test/resources/data/csv/input_indexed/metadata.csv index 89a54fcbb6c9..443bcc3d91c8 100644 --- a/gradoop-flink/src/test/resources/data/csv/input_indexed/metadata.csv +++ b/gradoop-flink/src/test/resources/data/csv/input_indexed/metadata.csv @@ -1,4 +1,4 @@ -v;A;a:string,b:int,c:float +v;A;a:string,b:int,c:float,d:null v;B;a:long,b:boolean,c:double e;a;a:int,b:float e;b;a:long \ No newline at end of file diff --git a/gradoop-flink/src/test/resources/data/csv/input_indexed/vertices/A/data.csv b/gradoop-flink/src/test/resources/data/csv/input_indexed/vertices/A/data.csv index b2740a4cb513..a148c288f422 100644 --- a/gradoop-flink/src/test/resources/data/csv/input_indexed/vertices/A/data.csv +++ b/gradoop-flink/src/test/resources/data/csv/input_indexed/vertices/A/data.csv @@ -1,2 +1,2 @@ -000000000000000000000000;A;foo|42|13.37 +000000000000000000000000;A;foo|42|13.37|null 000000000000000000000001;A;bar|23|19.84 \ No newline at end of file diff --git a/gradoop-flink/src/test/resources/data/tlf/io_test_string_without_edges.tlf b/gradoop-flink/src/test/resources/data/tlf/io_test_string_without_edges.tlf new file mode 100644 index 000000000000..f6fc94822a6f --- /dev/null +++ b/gradoop-flink/src/test/resources/data/tlf/io_test_string_without_edges.tlf @@ -0,0 +1,6 @@ +t # 0 +v 0 A +v 1 B +t # 1 +v 0 A +v 1 B diff --git a/gradoop-store/gradoop-accumulo/pom.xml b/gradoop-store/gradoop-accumulo/pom.xml index 3d1745d6c18a..fc841c619659 100644 --- a/gradoop-store/gradoop-accumulo/pom.xml +++ b/gradoop-store/gradoop-accumulo/pom.xml @@ -5,7 +5,7 @@ gradoop-store org.gradoop - 0.5.0-SNAPSHOT + 0.4.1 4.0.0 @@ -163,6 +163,10 @@ + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/config/GradoopAccumuloConfig.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/config/GradoopAccumuloConfig.java index 0edab9b9349d..16472f2dcac4 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/config/GradoopAccumuloConfig.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/config/GradoopAccumuloConfig.java @@ -16,7 +16,6 @@ package org.gradoop.storage.config; import org.apache.accumulo.core.security.Authorizations; -import org.apache.flink.api.java.ExecutionEnvironment; import org.gradoop.common.model.impl.pojo.EdgeFactory; import org.gradoop.common.model.impl.pojo.GraphHeadFactory; import org.gradoop.common.model.impl.pojo.VertexFactory; @@ -27,14 +26,12 @@ import org.gradoop.storage.impl.accumulo.handler.AccumuloGraphHandler; import org.gradoop.storage.impl.accumulo.handler.AccumuloVertexHandler; -import javax.annotation.Nonnull; import java.util.Properties; /** * Gradoop Accumulo configuration define */ -public class GradoopAccumuloConfig extends - GradoopStoreConfig { +public class GradoopAccumuloConfig implements GradoopStoreConfig { /** * accumulo user for accumulo connector, default "root" @@ -77,7 +74,7 @@ public class GradoopAccumuloConfig extends public static final String ZOOKEEPER_HOSTS = "zookeeper.hosts"; /** - * define for serialize version control + * Definition for serialize version control */ private static final int serialVersionUID = 23; @@ -89,17 +86,17 @@ public class GradoopAccumuloConfig extends /** * row handler for EPGM GraphHead */ - private transient AccumuloGraphHandler graphHandler; + private final AccumuloGraphHandler graphHandler; /** * row handler for EPGM Vertex */ - private transient AccumuloVertexHandler vertexHandler; + private final AccumuloVertexHandler vertexHandler; /** * row handler for EPGM Edge */ - private transient AccumuloEdgeHandler edgeHandler; + private final AccumuloEdgeHandler edgeHandler; /** * Creates a new Configuration. @@ -107,59 +104,31 @@ public class GradoopAccumuloConfig extends * @param graphHandler graph head handler * @param vertexHandler vertex handler * @param edgeHandler edge handler - * @param env flink execution environment */ private GradoopAccumuloConfig( AccumuloGraphHandler graphHandler, AccumuloVertexHandler vertexHandler, - AccumuloEdgeHandler edgeHandler, - ExecutionEnvironment env + AccumuloEdgeHandler edgeHandler ) { - super(new GraphHeadFactory(), new VertexFactory(), new EdgeFactory(), env); this.graphHandler = graphHandler; this.vertexHandler = vertexHandler; this.edgeHandler = edgeHandler; } - /** - * Creates a new Configuration. - * - * @param config Gradoop configuration - */ - private GradoopAccumuloConfig(GradoopAccumuloConfig config) { - this(config.graphHandler, config.vertexHandler, config.edgeHandler, - config.getExecutionEnvironment()); - this.accumuloProperties.putAll(config.accumuloProperties); - } - /** * Creates a default Configuration using POJO handlers for vertices, edges * and graph heads and default table names. * - * @param env apache flink execution environment * @return Default Gradoop Accumulo configuration. */ - public static GradoopAccumuloConfig getDefaultConfig( - ExecutionEnvironment env - ) { + public static GradoopAccumuloConfig getDefaultConfig() { GraphHeadFactory graphHeadFactory = new GraphHeadFactory(); EdgeFactory edgeFactory = new EdgeFactory(); VertexFactory vertexFactory = new VertexFactory(); return new GradoopAccumuloConfig( new AccumuloGraphHandler(graphHeadFactory), new AccumuloVertexHandler(vertexFactory), - new AccumuloEdgeHandler(edgeFactory), - env); - } - - /** - * Creates a Gradoop Accumulo configuration based on the given arguments. - * - * @param gradoopConfig Gradoop configuration - * @return Gradoop HBase configuration - */ - public static GradoopAccumuloConfig createConfig(@Nonnull GradoopAccumuloConfig gradoopConfig) { - return new GradoopAccumuloConfig(gradoopConfig); + new AccumuloEdgeHandler(edgeFactory)); } /** @@ -169,10 +138,7 @@ public static GradoopAccumuloConfig createConfig(@Nonnull GradoopAccumuloConfig * @param value property value * @return configure itself */ - public GradoopAccumuloConfig set( - String key, - Object value - ) { + public GradoopAccumuloConfig set(String key, Object value) { accumuloProperties.put(key, value); return this; } @@ -185,10 +151,7 @@ public GradoopAccumuloConfig set( * @param value template * @return integer value */ - public T get( - String key, - T defValue - ) { + public T get(String key, T defValue) { Object value = accumuloProperties.get(key); if (value == null) { return defValue; @@ -198,18 +161,38 @@ public T get( } } + /** + * Get accumulo properties + * + * @return accumulo properties + */ public Properties getAccumuloProperties() { return accumuloProperties; } + /** + * Get graph handler + * + * @return graph handler + */ public AccumuloGraphHandler getGraphHandler() { return graphHandler; } + /** + * Get vertex handler + * + * @return vertex handler + */ public AccumuloVertexHandler getVertexHandler() { return vertexHandler; } + /** + * Get edge handler + * + * @return edge handler + */ public AccumuloEdgeHandler getEdgeHandler() { return edgeHandler; } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/AccumuloEPGMStore.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/AccumuloEPGMStore.java index 0ac9add12c93..b145cd29a585 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/AccumuloEPGMStore.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/AccumuloEPGMStore.java @@ -34,7 +34,6 @@ import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.SortedKeyValueIterator; -import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.common.model.api.entities.EPGMEdge; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.common.model.api.entities.EPGMGraphHead; @@ -50,6 +49,7 @@ import org.gradoop.storage.common.iterator.EmptyClosableIterator; import org.gradoop.storage.common.predicate.query.ElementQuery; import org.gradoop.storage.common.predicate.query.Query; +import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.storage.impl.accumulo.constants.AccumuloDefault; import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; import org.gradoop.storage.impl.accumulo.handler.AccumuloRowHandler; @@ -130,8 +130,8 @@ public class AccumuloEPGMStore implements * etc. * @throws AccumuloException generic Accumulo Exception for general accumulo failures. */ - public AccumuloEPGMStore(@Nonnull GradoopAccumuloConfig config) throws - AccumuloSecurityException, AccumuloException { + public AccumuloEPGMStore(@Nonnull GradoopAccumuloConfig config) + throws AccumuloSecurityException, AccumuloException { this.config = config; this.conn = createConnector(); createTablesIfNotExists(); @@ -198,9 +198,6 @@ public void writeVertex(@Nonnull EPGMVertex record) { @Override public void writeEdge(@Nonnull EPGMEdge record) { writeRecord(record, edgeWriter, config.getEdgeHandler()); - // TODO: [#833] add Edge-in and edge-out - //writeEdgeOut(record); - //writeEdgeIn(record); } @Override @@ -471,38 +468,4 @@ private void createTablesIfNotExists() throws AccumuloSecurityException, Accumul } } - /** - * Write an edge-out link record into vertex table - * - * @param record epgm edge record - */ - private void writeEdgeOut(EPGMEdge record) { - //write out mutation - try { - Mutation mutation = new Mutation(record.getSourceId().toString()); - mutation = config.getVertexHandler() - .writeLink(mutation, record, false); - vertexWriter.addMutation(mutation); - } catch (MutationsRejectedException e) { - throw new RuntimeException(e); - } - } - - /** - * Write an edge-in link record into vertex table - * - * @param record epgm edge record - */ - private void writeEdgeIn(EPGMEdge record) { - //write out mutation - try { - Mutation mutation = new Mutation(record.getTargetId().toString()); - mutation = config.getVertexHandler() - .writeLink(mutation, record, true); - vertexWriter.addMutation(mutation); - } catch (MutationsRejectedException e) { - throw new RuntimeException(e); - } - } - } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloEdgeHandler.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloEdgeHandler.java index 0eb8a3786fba..bb528ad25662 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloEdgeHandler.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloEdgeHandler.java @@ -71,7 +71,6 @@ public Mutation writeRow( return mutation; } - @Override public Edge readRow(EPGMEdge origin) { return factory.initEdge( diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloGraphHandler.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloGraphHandler.java index 5de59cba1861..a09ff6cda716 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloGraphHandler.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloGraphHandler.java @@ -66,5 +66,4 @@ public GraphHead readRow(EPGMGraphHead origin) { /*properties*/origin.getProperties()); } - } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloRowHandler.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloRowHandler.java index 4918ca85e88d..72d99b49fc1a 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloRowHandler.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloRowHandler.java @@ -17,17 +17,21 @@ import org.apache.accumulo.core.data.Mutation; import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.common.model.impl.pojo.Element; + +import java.io.Serializable; /** - * accumulo row handler + * Accumulo row handler * - * @param row to read - * @param row to store + * @param row to read from DB (some element) + * @param row to write into DB (some EPGM element) */ -public interface AccumuloRowHandler { +public interface AccumuloRowHandler + extends Serializable { /** - * write element to store + * Write element to store * * @param mutation new row mutation * @param record EPGMElement to be write @@ -39,7 +43,7 @@ Mutation writeRow( ); /** - * read row from origin epgm definition + * Read row from origin epgm definition * * @param origin origin epgm definition * @return epgm row diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloVertexHandler.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloVertexHandler.java index 1236eb3b648b..321a040d28b1 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloVertexHandler.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/handler/AccumuloVertexHandler.java @@ -17,7 +17,6 @@ import org.apache.accumulo.core.data.Mutation; import org.apache.accumulo.core.data.Value; -import org.gradoop.common.model.api.entities.EPGMEdge; import org.gradoop.common.model.api.entities.EPGMVertex; import org.gradoop.common.model.api.entities.EPGMVertexFactory; import org.gradoop.common.model.impl.id.GradoopIdSet; @@ -25,7 +24,7 @@ import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; /** - * accumulo vertex handler for row's read/write operator + * Accumulo vertex handler for row's read/write operator */ public class AccumuloVertexHandler implements AccumuloRowHandler { @@ -78,25 +77,4 @@ public Vertex readRow(EPGMVertex origin) { ); } - /** - * write link edge to store - * - * @param mutation new row mutation - * @param edge link epgm edge - * @param isEdgeIn if this is in-edg (not out-edge) - * @return mutation instance - */ - public Mutation writeLink( - Mutation mutation, - EPGMEdge edge, - boolean isEdgeIn - ) { - mutation.put( - /*cf*/isEdgeIn ? AccumuloTables.KEY.EDGE_IN : AccumuloTables.KEY.EDGE_OUT, - /*cq*/edge.getId().toString(), - /*value*/isEdgeIn ? edge.getSourceId().toString() : edge.getTargetId().toString()); - - return mutation; - } - } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloBase.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloBase.java index 6791d0c2553a..ebf2af96ad60 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloBase.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloBase.java @@ -15,9 +15,12 @@ */ package org.gradoop.storage.impl.accumulo.io; +import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; +import javax.annotation.Nonnull; + /** * Base class for Accumulo data source and sink. */ @@ -28,21 +31,50 @@ abstract class AccumuloBase { */ private final AccumuloEPGMStore epgmStore; + /** + * Gradoop flink configuration + */ + private final GradoopFlinkConfig flinkConfig; + /** * Creates a new Accumulo data source/sink. * * @param epgmStore store implementation + * @param flinkConfig gradoop flink config */ - AccumuloBase(AccumuloEPGMStore epgmStore) { + AccumuloBase( + @Nonnull AccumuloEPGMStore epgmStore, + @Nonnull GradoopFlinkConfig flinkConfig + ) { + this.flinkConfig = flinkConfig; this.epgmStore = epgmStore; } + /** + * Get Accumulo EPGM Store instance + * + * @return accumulo epgm store instance + */ AccumuloEPGMStore getStore() { return epgmStore; } + /** + * Get accumulo configuration + * + * @return accumulo configuration + */ GradoopAccumuloConfig getAccumuloConfig() { return epgmStore.getConfig(); } + /** + * Get flink configuration + * + * @return flink configuration + */ + GradoopFlinkConfig getFlinkConfig() { + return flinkConfig; + } + } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSink.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSink.java index c5492c49187c..8cba462b0bcf 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSink.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSink.java @@ -15,13 +15,17 @@ */ package org.gradoop.storage.impl.accumulo.io; -import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.flink.io.api.DataSink; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.LogicalGraph; -import org.gradoop.storage.impl.accumulo.io.outputformats.EdgeOutputFormat; -import org.gradoop.storage.impl.accumulo.io.outputformats.GraphHeadOutputFormat; -import org.gradoop.storage.impl.accumulo.io.outputformats.VertexOutputFormat; +import org.gradoop.flink.util.GradoopFlinkConfig; +import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; +import org.gradoop.storage.impl.accumulo.io.outputformats.ElementOutputFormat; + +import javax.annotation.Nonnull; /** * Write graph or graph collection into accumulo store @@ -29,12 +33,16 @@ public class AccumuloDataSink extends AccumuloBase implements DataSink { /** - * Creates a new Accumulo data source/sink. + * Creates a new Accumulo data sink. * * @param store store implementation + * @param flinkConfig gradoop flink configuration */ - public AccumuloDataSink(AccumuloEPGMStore store) { - super(store); + public AccumuloDataSink( + @Nonnull AccumuloEPGMStore store, + @Nonnull GradoopFlinkConfig flinkConfig + ) { + super(store, flinkConfig); } @Override @@ -48,29 +56,18 @@ public void write(GraphCollection graphCollection) { } @Override - public void write( - LogicalGraph logicalGraph, - boolean overwrite - ) { - write(getAccumuloConfig().getGraphCollectionFactory().fromGraph(logicalGraph), overwrite); + public void write(LogicalGraph logicalGraph, boolean overwrite) { + write(getFlinkConfig().getGraphCollectionFactory().fromGraph(logicalGraph), overwrite); } @Override - public void write( - GraphCollection graphCollection, - boolean overWrite - ) { - graphCollection.getGraphHeads().output( - new GraphHeadOutputFormat(getAccumuloConfig().getAccumuloProperties())); - graphCollection.getVertices().output( - new VertexOutputFormat(getAccumuloConfig().getAccumuloProperties())); - graphCollection.getEdges().output( - new EdgeOutputFormat(getAccumuloConfig().getAccumuloProperties())); - // TODO: [#833] add Edge-in and edge-out - //graphCollection.getEdges().output( - // new EdgeOutOutputFormat(getAccumuloConfig().getAccumuloProperties())); - //graphCollection.getEdges().output( - // new EdgeInOutputFormat(getAccumuloConfig().getAccumuloProperties())); + public void write(GraphCollection graphCollection, boolean overWrite) { + graphCollection.getGraphHeads() + .output(new ElementOutputFormat<>(GraphHead.class, getAccumuloConfig())); + graphCollection.getVertices() + .output(new ElementOutputFormat<>(Vertex.class, getAccumuloConfig())); + graphCollection.getEdges() + .output(new ElementOutputFormat<>(Edge.class, getAccumuloConfig())); } } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSource.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSource.java index aa06f06716ea..c47a1cd8ef65 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSource.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/AccumuloDataSource.java @@ -19,13 +19,14 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.storage.common.predicate.query.ElementQuery; -import org.gradoop.storage.common.io.FilterableDataSource; -import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.GraphCollectionFactory; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.operators.combination.ReduceCombination; +import org.gradoop.flink.util.GradoopFlinkConfig; +import org.gradoop.storage.common.io.FilterableDataSource; +import org.gradoop.storage.common.predicate.query.ElementQuery; +import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; import org.gradoop.storage.impl.accumulo.io.inputformats.EdgeInputFormat; import org.gradoop.storage.impl.accumulo.io.inputformats.GraphHeadInputFormat; import org.gradoop.storage.impl.accumulo.io.inputformats.VertexInputFormat; @@ -62,26 +63,32 @@ public class AccumuloDataSource extends AccumuloBase implements FilterableDataSo * Creates a new Accumulo data source. * * @param store accumulo epgm store + * @param config gradoop flink configuration */ - public AccumuloDataSource(@Nonnull AccumuloEPGMStore store) { - this(store, null, null, null); + public AccumuloDataSource( + @Nonnull AccumuloEPGMStore store, + @Nonnull GradoopFlinkConfig config + ) { + this(store, config, null, null, null); } /** * Creates a new Accumulo data source. * * @param store accumulo epgm store + * @param config gradoop flink configuration * @param graphQuery graph head filter * @param vertexQuery vertex filter * @param edgeQuery edge filter */ private AccumuloDataSource( @Nonnull AccumuloEPGMStore store, + @Nonnull GradoopFlinkConfig config, @Nullable AccumuloQueryHolder graphQuery, @Nullable AccumuloQueryHolder vertexQuery, @Nullable AccumuloQueryHolder edgeQuery ) { - super(store); + super(store, config); this.graphHeadQuery = graphQuery; this.vertexQuery = vertexQuery; this.edgeQuery = edgeQuery; @@ -94,8 +101,8 @@ public LogicalGraph getLogicalGraph() { @Override public GraphCollection getGraphCollection() { - GraphCollectionFactory factory = getAccumuloConfig().getGraphCollectionFactory(); - ExecutionEnvironment env = getAccumuloConfig().getExecutionEnvironment(); + GraphCollectionFactory factory = getFlinkConfig().getGraphCollectionFactory(); + ExecutionEnvironment env = getFlinkConfig().getExecutionEnvironment(); return factory.fromDataSets( /*graph head format*/ env.createInput(new GraphHeadInputFormat( @@ -117,6 +124,7 @@ public AccumuloDataSource applyGraphPredicate( AccumuloQueryHolder newGraphQuery = AccumuloQueryHolder.create(query); return new AccumuloDataSource( getStore(), + getFlinkConfig(), newGraphQuery, vertexQuery, edgeQuery @@ -131,6 +139,7 @@ public AccumuloDataSource applyVertexPredicate( AccumuloQueryHolder newVertexQuery = AccumuloQueryHolder.create(query); return new AccumuloDataSource( getStore(), + getFlinkConfig(), graphHeadQuery, newVertexQuery, edgeQuery @@ -145,6 +154,7 @@ public AccumuloDataSource applyEdgePredicate( AccumuloQueryHolder newEdgeQuery = AccumuloQueryHolder.create(query); return new AccumuloDataSource( getStore(), + getFlinkConfig(), graphHeadQuery, vertexQuery, newEdgeQuery diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/inputformats/BaseInputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/inputformats/BaseInputFormat.java index cb3784976a5d..8c610a7d4ef3 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/inputformats/BaseInputFormat.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/inputformats/BaseInputFormat.java @@ -35,8 +35,8 @@ import org.apache.flink.core.io.GenericInputSplit; import org.apache.hadoop.mapred.InputSplit; import org.apache.hadoop.mapred.JobConf; -import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.common.model.impl.pojo.Element; +import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.storage.impl.accumulo.constants.AccumuloDefault; import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; import org.gradoop.storage.impl.accumulo.predicate.query.AccumuloQueryHolder; diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/BaseOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/BaseOutputFormat.java deleted file mode 100644 index a518a43e3145..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/BaseOutputFormat.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.client.AccumuloException; -import org.apache.accumulo.core.client.AccumuloSecurityException; -import org.apache.accumulo.core.client.BatchWriter; -import org.apache.accumulo.core.client.BatchWriterConfig; -import org.apache.accumulo.core.client.Connector; -import org.apache.accumulo.core.client.MutationsRejectedException; -import org.apache.accumulo.core.client.TableNotFoundException; -import org.apache.accumulo.core.client.ZooKeeperInstance; -import org.apache.accumulo.core.client.security.tokens.PasswordToken; -import org.apache.accumulo.core.data.Mutation; -import org.apache.flink.api.common.io.OutputFormat; -import org.apache.flink.configuration.Configuration; -import org.gradoop.storage.config.GradoopAccumuloConfig; -import org.gradoop.common.model.impl.pojo.Element; -import org.gradoop.storage.impl.accumulo.constants.AccumuloDefault; - -import java.io.IOException; -import java.util.Properties; - -/** - * Common Abstract {@link OutputFormat} for gradoop accumulo store - * - * @param gradoop element - */ -public abstract class BaseOutputFormat implements OutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * Accumulo client properties - */ - private final Properties properties; - - /** - * Accumulo batch writer - */ - private transient BatchWriter writer; - - /** - * Create a new output format for gradoop element - * - * @param properties accumulo properties - */ - BaseOutputFormat(Properties properties) { - this.properties = properties; - } - - /** - * Invoke hook after connector initiate - */ - protected abstract void initiate(); - - /** - * Get table name with prefix configuration - * - * @param prefix prefix configuration - * @return table name - */ - protected abstract String getTableName(String prefix); - - /** - * Write element record to mutation - * - * @param record element record - * @return mutation after writing - */ - protected abstract Mutation writeMutation(E record); - - @Override - public void configure(Configuration parameters) { - //do nothing - } - - @Override - public final void open( - int taskNumber, - int numTasks - ) { - String user = (String) properties - .getOrDefault(GradoopAccumuloConfig.ACCUMULO_USER, AccumuloDefault.USER); - String password = (String) properties - .getOrDefault(GradoopAccumuloConfig.ACCUMULO_PASSWD, AccumuloDefault.PASSWORD); - String instance = (String) properties - .getOrDefault(GradoopAccumuloConfig.ACCUMULO_INSTANCE, AccumuloDefault.INSTANCE); - String zkHosts = (String) properties - .getOrDefault(GradoopAccumuloConfig.ZOOKEEPER_HOSTS, AccumuloDefault.INSTANCE); - String tableName = getTableName((String) properties - .getOrDefault(GradoopAccumuloConfig.ACCUMULO_TABLE_PREFIX, AccumuloDefault.TABLE_PREFIX)); - try { - //create connector - Connector conn = new ZooKeeperInstance(instance, zkHosts) - .getConnector(user, new PasswordToken(password)); - //create batch writer - writer = conn.createBatchWriter(tableName, new BatchWriterConfig()); - initiate(); - } catch (AccumuloException | AccumuloSecurityException | TableNotFoundException e) { - throw new ExceptionInInitializerError(e); - } - } - - @Override - public final void writeRecord(E record) throws IOException { - try { - Mutation mutation = writeMutation(record); - writer.addMutation(mutation); - } catch (MutationsRejectedException e) { - throw new IOException(e); - } - } - - @Override - public final void close() throws IOException { - if (writer != null) { - try { - writer.close(); - } catch (MutationsRejectedException e) { - throw new IOException(e); - } - } - } -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeInOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeInOutputFormat.java deleted file mode 100644 index 82dd0d9910a8..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeInOutputFormat.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.data.Mutation; -import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.VertexFactory; -import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; -import org.gradoop.storage.impl.accumulo.handler.AccumuloVertexHandler; - -import java.util.Properties; - -/** - * Edge-In OutputFormat - */ -public class EdgeInOutputFormat extends BaseOutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * vertex handler - */ - private transient AccumuloVertexHandler handler; - - /** - * Create a new output format for gradoop edge-in - * - * @param properties accumulo properties - */ - public EdgeInOutputFormat(Properties properties) { - super(properties); - } - - @Override - protected void initiate() { - handler = new AccumuloVertexHandler(new VertexFactory()); - } - - @Override - protected String getTableName(String prefix) { - return String.format("%s%s", prefix, AccumuloTables.VERTEX); - } - - @Override - protected Mutation writeMutation(Edge record) { - //write out mutation - Mutation mutation = new Mutation(record.getSourceId().toString()); - mutation = handler.writeLink(mutation, record, true); - return mutation; - } - -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutOutputFormat.java deleted file mode 100644 index 8412c0b7213e..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutOutputFormat.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.data.Mutation; -import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.VertexFactory; -import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; -import org.gradoop.storage.impl.accumulo.handler.AccumuloVertexHandler; - -import java.util.Properties; - -/** - * Edge-Out OutputFormat - */ -public class EdgeOutOutputFormat extends BaseOutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * vertex handler - */ - private transient AccumuloVertexHandler handler; - - /** - * Create a new output format for gradoop edge-out - * - * @param properties accumulo properties - */ - public EdgeOutOutputFormat(Properties properties) { - super(properties); - } - - @Override - protected void initiate() { - handler = new AccumuloVertexHandler(new VertexFactory()); - } - - @Override - protected String getTableName(String prefix) { - return String.format("%s%s", prefix, AccumuloTables.VERTEX); - } - - @Override - protected Mutation writeMutation(Edge record) { - //write out mutation - Mutation mutation = new Mutation(record.getSourceId().toString()); - mutation = handler.writeLink(mutation, record, false); - return mutation; - } - -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutputFormat.java deleted file mode 100644 index eb0b1b3cda99..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/EdgeOutputFormat.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.data.Mutation; -import org.gradoop.common.model.impl.pojo.Edge; -import org.gradoop.common.model.impl.pojo.EdgeFactory; -import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; -import org.gradoop.storage.impl.accumulo.handler.AccumuloEdgeHandler; - -import java.util.Properties; - -/** - * Edge OutputFormat, write edge data set into accumulo store - */ -public class EdgeOutputFormat extends BaseOutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * accumulo edge handler - */ - private transient AccumuloEdgeHandler handler; - - /** - * Create a new output format for gradoop edge - * - * @param properties accumulo properties - */ - public EdgeOutputFormat(Properties properties) { - super(properties); - } - - @Override - protected void initiate() { - handler = new AccumuloEdgeHandler(new EdgeFactory()); - } - - @Override - protected String getTableName(String prefix) { - return String.format("%s%s", prefix, AccumuloTables.EDGE); - } - - @Override - protected Mutation writeMutation(Edge record) { - Mutation mutation = new Mutation(record.getId().toString()); - return handler.writeRow(mutation, record); - } - -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/ElementOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/ElementOutputFormat.java new file mode 100644 index 000000000000..dfb3cc81f543 --- /dev/null +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/ElementOutputFormat.java @@ -0,0 +1,119 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.accumulo.io.outputformats; + +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.flink.api.common.io.OutputFormat; +import org.apache.flink.configuration.Configuration; +import org.gradoop.common.model.api.entities.EPGMEdge; +import org.gradoop.common.model.api.entities.EPGMGraphHead; +import org.gradoop.common.model.api.entities.EPGMVertex; +import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.common.model.impl.pojo.Element; +import org.gradoop.common.model.impl.pojo.GraphHead; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.storage.common.api.EPGMGraphOutput; +import org.gradoop.storage.config.GradoopAccumuloConfig; +import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; + +import javax.annotation.Nonnull; +import java.io.IOException; + +/** + * Common {@link OutputFormat} for gradoop accumulo store + * + * @param gradoop element + */ +public class ElementOutputFormat implements OutputFormat { + + /** + * serialize id + */ + private static final int serialVersionUID = 0x1; + + /** + * Gradoop accumulo configuration + */ + private final GradoopAccumuloConfig config; + + /** + * Element type + */ + private final Class elementType; + + /** + * Client writer cache count + */ + private int cacheCount; + + /** + * Accumulo batch writer + */ + private transient AccumuloEPGMStore store; + + /** + * Create a new output format for gradoop element + * + * @param elementType output element type + * @param config gradoop accumulo configuration + */ + public ElementOutputFormat(@Nonnull Class elementType, @Nonnull GradoopAccumuloConfig config) { + this.elementType = elementType; + this.config = config; + } + + + @Override + public void configure(Configuration configuration) { + // do nothing + } + + + @Override + public final void open(int taskNumber, int numTasks) throws IOException { + try { + this.store = new AccumuloEPGMStore(config); + } catch (AccumuloSecurityException | AccumuloException e) { + throw new IOException(e); + } + } + + + @Override + public final void writeRecord(E record) { + if (elementType == Edge.class) { + this.store.writeEdge((EPGMEdge) record); + } else if (elementType == Vertex.class) { + this.store.writeVertex((EPGMVertex) record); + } else if (elementType == GraphHead.class) { + this.store.writeGraphHead((EPGMGraphHead) record); + } else { + throw new IllegalArgumentException(String.format("illegal element type %s", elementType)); + } + cacheCount++; + if (cacheCount % EPGMGraphOutput.DEFAULT_CACHE_SIZE == 0) { + store.flush(); + } + } + + + @Override + public final void close() { + store.flush(); + store.close(); + } +} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/GraphHeadOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/GraphHeadOutputFormat.java deleted file mode 100644 index b0dc8d6f20d7..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/GraphHeadOutputFormat.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.data.Mutation; -import org.gradoop.common.model.impl.pojo.GraphHead; -import org.gradoop.common.model.impl.pojo.GraphHeadFactory; -import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; -import org.gradoop.storage.impl.accumulo.handler.AccumuloGraphHandler; - -import java.util.Properties; - -/** - * Graph Head OutputFormat, write graph head data set into accumulo store - */ -public class GraphHeadOutputFormat extends BaseOutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * graph head handler - */ - private transient AccumuloGraphHandler handler; - - /** - * Create a new output format for gradoop graph head - * - * @param properties accumulo properties - */ - public GraphHeadOutputFormat(Properties properties) { - super(properties); - } - - @Override - protected void initiate() { - handler = new AccumuloGraphHandler(new GraphHeadFactory()); - } - - @Override - protected String getTableName(String prefix) { - return String.format("%s%s", prefix, AccumuloTables.GRAPH); - } - - @Override - protected Mutation writeMutation(GraphHead record) { - Mutation mutation = new Mutation(record.getId().toString()); - return handler.writeRow(mutation, record); - } - -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/VertexOutputFormat.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/VertexOutputFormat.java deleted file mode 100644 index f86c4aacb2a5..000000000000 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/VertexOutputFormat.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.accumulo.io.outputformats; - -import org.apache.accumulo.core.data.Mutation; -import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.common.model.impl.pojo.VertexFactory; -import org.gradoop.storage.impl.accumulo.constants.AccumuloTables; -import org.gradoop.storage.impl.accumulo.handler.AccumuloVertexHandler; - -import java.util.Properties; - -/** - * Vertex output format, write vertex data set into accumulo store - */ -public class VertexOutputFormat extends BaseOutputFormat { - - /** - * serialize id - */ - private static final int serialVersionUID = 0x1; - - /** - * vertex handler - */ - private transient AccumuloVertexHandler handler; - - /** - * Create a new output format for gradoop vertex - * - * @param properties accumulo properties - */ - public VertexOutputFormat(Properties properties) { - super(properties); - } - - @Override - protected void initiate() { - handler = new AccumuloVertexHandler(new VertexFactory()); - } - - @Override - protected String getTableName(String prefix) { - return String.format("%s%s", prefix, AccumuloTables.VERTEX); - } - - @Override - protected Mutation writeMutation(Vertex record) { - Mutation mutation = new Mutation(record.getId().toString()); - return handler.writeRow(mutation, record); - } - -} diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/package-info.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/package-info.java index ceed2863922a..fd28dd8f1f64 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/package-info.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/io/outputformats/package-info.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** - * Contains output format classes for accumulo store + * Gradoop Accumulo OutputFormat */ package org.gradoop.storage.impl.accumulo.io.outputformats; diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/iterator/client/ClientClosableIterator.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/iterator/client/ClientClosableIterator.java index 51928216ac3d..239c2c1afd4e 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/iterator/client/ClientClosableIterator.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/iterator/client/ClientClosableIterator.java @@ -19,6 +19,7 @@ import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.common.model.impl.pojo.Element; import org.gradoop.storage.common.api.EPGMGraphOutput; import org.gradoop.storage.common.api.EPGMGraphPredictableOutput; import org.gradoop.storage.common.iterator.ClosableIterator; @@ -44,7 +45,7 @@ * @see EPGMGraphOutput * @see EPGMGraphPredictableOutput */ -public class ClientClosableIterator +public class ClientClosableIterator implements ClosableIterator { /** diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/api/AccumuloElementFilter.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/api/AccumuloElementFilter.java index f5f6b6d917ad..afbb82a97704 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/api/AccumuloElementFilter.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/api/AccumuloElementFilter.java @@ -20,9 +20,9 @@ import org.gradoop.storage.impl.accumulo.iterator.tserver.GradoopEdgeIterator; import org.gradoop.storage.impl.accumulo.iterator.tserver.GradoopGraphHeadIterator; import org.gradoop.storage.impl.accumulo.iterator.tserver.GradoopVertexIterator; -import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.AND; -import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.NOT; -import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.OR; +import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.And; +import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.Not; +import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.Or; import javax.annotation.Nonnull; import java.io.ByteArrayInputStream; @@ -92,7 +92,7 @@ default String encode() { */ @Nonnull default AccumuloElementFilter or(@Nonnull AccumuloElementFilter another) { - return OR.create(this, another); + return Or.create(this, another); } /** @@ -103,7 +103,7 @@ default AccumuloElementFilter or(@Nonnull AccumuloElementFilter another) { */ @Nonnull default AccumuloElementFilter and(@Nonnull AccumuloElementFilter another) { - return AND.create(this, another); + return And.create(this, another); } /** @@ -112,7 +112,7 @@ default AccumuloElementFilter and(@Nonnull AccumuloElementFilter another) */ @Nonnull default AccumuloElementFilter negate() { - return NOT.of(this); + return Not.of(this); } } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/AND.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/And.java similarity index 88% rename from gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/AND.java rename to gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/And.java index 40673c1bd0ec..4fe56077d570 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/AND.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/And.java @@ -24,14 +24,14 @@ import java.util.StringJoiner; /** - * conjunctive predicate filter + * Conjunctive predicate filter * * @param element type */ -public final class AND implements AccumuloElementFilter { +public final class And implements AccumuloElementFilter { /** - * predicate list + * Predicate list */ private final List> predicates = new ArrayList<>(); @@ -40,7 +40,7 @@ public final class AND implements AccumuloElementFilter> predicates) { + private And(List> predicates) { if (predicates.size() < 2) { throw new IllegalArgumentException(String.format("predicates len(=%d) < 2", predicates.size())); @@ -56,10 +56,10 @@ private AND(List> predicates) { * @return Conjunctive filter instance */ @SafeVarargs - public static AND create(AccumuloElementFilter... predicates) { + public static And create(AccumuloElementFilter... predicates) { List> formula = new ArrayList<>(); Collections.addAll(formula, predicates); - return new AND<>(formula); + return new And<>(formula); } @Override diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/NOT.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Not.java similarity index 82% rename from gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/NOT.java rename to gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Not.java index 0e27bb52b09a..4f3f3597080d 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/NOT.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Not.java @@ -19,23 +19,23 @@ import org.gradoop.storage.impl.accumulo.predicate.filter.api.AccumuloElementFilter; /** - * negative logic filter + * Negative logic filter * * @param input type */ -public final class NOT implements AccumuloElementFilter { +public final class Not implements AccumuloElementFilter { /** - * predicate list + * The predicate to negate */ private final AccumuloElementFilter predicate; /** - * Create a new predicate to be conjunction + * Create a new negated predicate * * @param predicate predicate */ - private NOT(AccumuloElementFilter predicate) { + private Not(AccumuloElementFilter predicate) { this.predicate = predicate; } @@ -46,8 +46,8 @@ private NOT(AccumuloElementFilter predicate) { * @param input type * @return negative filter instance */ - public static NOT of(AccumuloElementFilter predicate) { - return new NOT<>(predicate); + public static Not of(AccumuloElementFilter predicate) { + return new Not<>(predicate); } @Override diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/OR.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Or.java similarity index 88% rename from gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/OR.java rename to gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Or.java index a414245e9f52..f7772f1566e8 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/OR.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/filter/calculate/Or.java @@ -28,10 +28,10 @@ * * @param element type */ -public final class OR implements AccumuloElementFilter { +public final class Or implements AccumuloElementFilter { /** - * predicate list + * Predicate list */ private final List> predicates = new ArrayList<>(); @@ -40,7 +40,7 @@ public final class OR implements AccumuloElementFilter * * @param predicates predicates */ - private OR(List> predicates) { + private Or(List> predicates) { if (predicates.size() < 2) { throw new IllegalArgumentException(String.format("predicates len(=%d) < 2", predicates.size())); @@ -49,17 +49,17 @@ private OR(List> predicates) { } /** - * create a disjunctive formula + * Create a disjunctive formula * * @param predicates filter predicate * @param input type * @return Conjunctive filter instance */ @SafeVarargs - public static OR create(AccumuloElementFilter... predicates) { + public static Or create(AccumuloElementFilter... predicates) { List> formula = new ArrayList<>(); Collections.addAll(formula, predicates); - return new OR<>(formula); + return new Or<>(formula); } @Override diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/query/AccumuloQueryHolder.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/query/AccumuloQueryHolder.java index 3ce3bd72b33c..f6cacaef3e9b 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/query/AccumuloQueryHolder.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/impl/accumulo/predicate/query/AccumuloQueryHolder.java @@ -115,6 +115,11 @@ public List getQueryRanges() { return queryRanges == null ? null : RangeWrapper.decrypt(queryRanges).ranges; } + /** + * Get reduce filter + * + * @return accumulo element filter + */ public AccumuloElementFilter getReduceFilter() { return reduceFilter; } diff --git a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/utils/AccumuloFilters.java b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/utils/AccumuloFilters.java index 1262ae760e81..c7e4bbe33919 100644 --- a/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/utils/AccumuloFilters.java +++ b/gradoop-store/gradoop-accumulo/src/main/java/org/gradoop/storage/utils/AccumuloFilters.java @@ -26,12 +26,12 @@ import java.util.regex.Pattern; /** - * accumulo filters collection utils + * Accumulo filters collection utils */ public class AccumuloFilters { /** - * label in formula generator function + * Label in formula generator function * * @param value value ranges * @param epgm element type @@ -45,7 +45,7 @@ public static AccumuloLabelIn labelIn( } /** - * label regex formula generator function + * Label regex formula generator function * * @param reg regex pattern * @param epgm element type @@ -59,7 +59,7 @@ public static AccumuloLabelReg labelReg( } /** - * property equals formula generator function + * Property equals formula generator function * * @param key property key * @param value property value @@ -75,7 +75,7 @@ public static AccumuloPropEquals propEquals( } /** - * property larger than formula generator function + * Property larger than formula generator function * * @param key property key * @param value property value @@ -93,7 +93,7 @@ public static AccumuloPropLargerThan propLargerThan( } /** - * property regex formula generator function + * Property regex formula generator function * * @param key property key * @param reg property regex pattern diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloStoreTestBase.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloStoreTestBase.java index 2a574cc00784..87ad03be41cf 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloStoreTestBase.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloStoreTestBase.java @@ -16,12 +16,13 @@ package org.gradoop.storage.impl.accumulo; import org.gradoop.common.GradoopTestUtils; -import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.common.util.AsciiGraphLoader; import org.gradoop.flink.model.GradoopFlinkTestBase; +import org.gradoop.flink.util.GradoopFlinkConfig; +import org.gradoop.storage.config.GradoopAccumuloConfig; import java.util.ArrayList; import java.util.List; @@ -40,8 +41,7 @@ protected void doTest( String namespace, SocialTestContext context ) throws Throwable { - GradoopAccumuloConfig config = AccumuloTestSuite - .getAcConfig(getExecutionEnvironment(), namespace); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(namespace); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); //read vertices by label @@ -58,7 +58,8 @@ protected void doTest( } graphStore.flush(); - context.test(loader, graphStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + context.test(loader, graphStore, flinkConfig); } /** @@ -98,7 +99,8 @@ public interface SocialTestContext { void test( AsciiGraphLoader loader, - AccumuloEPGMStore store + AccumuloEPGMStore store, + GradoopFlinkConfig config ) throws Throwable; } diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloTestSuite.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloTestSuite.java index b613b99a602b..dcc4f18c952c 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloTestSuite.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/AccumuloTestSuite.java @@ -17,17 +17,17 @@ import org.apache.accumulo.minicluster.MiniAccumuloCluster; import org.apache.accumulo.minicluster.MiniAccumuloConfig; -import org.apache.flink.api.java.ExecutionEnvironment; +import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.storage.impl.accumulo.basic.StoreTest; -import org.gradoop.storage.impl.accumulo.predicate.StoreBasicPredicateTest; -import org.gradoop.storage.impl.accumulo.predicate.StoreIdsPredicateTest; -import org.gradoop.storage.impl.accumulo.predicate.StoreLabelPredicateTest; -import org.gradoop.storage.impl.accumulo.predicate.StorePropPredicateTest; import org.gradoop.storage.impl.accumulo.io.IOBasicTest; import org.gradoop.storage.impl.accumulo.io.source.IOEdgePredicateTest; import org.gradoop.storage.impl.accumulo.io.source.IOGraphPredicateTest; import org.gradoop.storage.impl.accumulo.io.source.IOVertexPredicateTest; +import org.gradoop.storage.impl.accumulo.predicate.StoreBasicPredicateTest; +import org.gradoop.storage.impl.accumulo.predicate.StoreIdsPredicateTest; +import org.gradoop.storage.impl.accumulo.predicate.StoreLabelPredicateTest; +import org.gradoop.storage.impl.accumulo.predicate.StorePropPredicateTest; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -39,7 +39,11 @@ import java.io.File; -import static org.gradoop.storage.config.GradoopAccumuloConfig.*; +import static org.gradoop.storage.config.GradoopAccumuloConfig.ACCUMULO_INSTANCE; +import static org.gradoop.storage.config.GradoopAccumuloConfig.ACCUMULO_PASSWD; +import static org.gradoop.storage.config.GradoopAccumuloConfig.ACCUMULO_TABLE_PREFIX; +import static org.gradoop.storage.config.GradoopAccumuloConfig.ACCUMULO_USER; +import static org.gradoop.storage.config.GradoopAccumuloConfig.ZOOKEEPER_HOSTS; /** * gradoop accumulo test suit @@ -94,11 +98,8 @@ public static MiniAccumuloCluster getAccumulo() { * @param prefix store prefix * @return gradoop accumulo configure */ - public static GradoopAccumuloConfig getAcConfig( - ExecutionEnvironment env, - String prefix - ) { - return GradoopAccumuloConfig.getDefaultConfig(env) + public static GradoopAccumuloConfig getAcConfig(String prefix) { + return GradoopAccumuloConfig.getDefaultConfig() .set(ACCUMULO_USER, "root") .set(ACCUMULO_INSTANCE, accumulo.getInstanceName()) .set(ZOOKEEPER_HOSTS, accumulo.getZooKeepers()) diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/basic/StoreTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/basic/StoreTest.java index 3feade784bda..c52d82b06b6a 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/basic/StoreTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/basic/StoreTest.java @@ -16,14 +16,12 @@ package org.gradoop.storage.impl.accumulo.basic; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import com.google.common.collect.Queues; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; -import org.gradoop.storage.impl.accumulo.AccumuloTestSuite; import org.gradoop.common.GradoopTestUtils; -import org.gradoop.storage.config.GradoopAccumuloConfig; import org.gradoop.common.config.GradoopConfig; +import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.common.model.api.entities.EPGMEdge; import org.gradoop.common.model.api.entities.EPGMGraphHead; import org.gradoop.common.model.api.entities.EPGMVertex; @@ -33,9 +31,12 @@ import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.common.model.impl.properties.Properties; -import org.gradoop.common.exceptions.UnsupportedTypeException; -import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; import org.gradoop.common.util.AsciiGraphLoader; +import org.gradoop.flink.util.GradoopFlinkConfig; +import org.gradoop.storage.config.GradoopAccumuloConfig; +import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; +import org.gradoop.storage.impl.accumulo.AccumuloTestSuite; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -43,9 +44,45 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import java.util.Set; - -import static org.gradoop.common.GradoopTestUtils.*; +import java.util.Queue; + +import static org.gradoop.common.GradoopTestUtils.BIG_DECIMAL_VAL_7; +import static org.gradoop.common.GradoopTestUtils.BOOL_VAL_1; +import static org.gradoop.common.GradoopTestUtils.DATETIME_VAL_d; +import static org.gradoop.common.GradoopTestUtils.DATE_VAL_b; +import static org.gradoop.common.GradoopTestUtils.DOUBLE_VAL_5; +import static org.gradoop.common.GradoopTestUtils.FLOAT_VAL_4; +import static org.gradoop.common.GradoopTestUtils.GRADOOP_ID_VAL_8; +import static org.gradoop.common.GradoopTestUtils.INT_VAL_2; +import static org.gradoop.common.GradoopTestUtils.KEY_0; +import static org.gradoop.common.GradoopTestUtils.KEY_1; +import static org.gradoop.common.GradoopTestUtils.KEY_2; +import static org.gradoop.common.GradoopTestUtils.KEY_3; +import static org.gradoop.common.GradoopTestUtils.KEY_4; +import static org.gradoop.common.GradoopTestUtils.KEY_5; +import static org.gradoop.common.GradoopTestUtils.KEY_6; +import static org.gradoop.common.GradoopTestUtils.KEY_7; +import static org.gradoop.common.GradoopTestUtils.KEY_8; +import static org.gradoop.common.GradoopTestUtils.KEY_9; +import static org.gradoop.common.GradoopTestUtils.KEY_a; +import static org.gradoop.common.GradoopTestUtils.KEY_b; +import static org.gradoop.common.GradoopTestUtils.KEY_c; +import static org.gradoop.common.GradoopTestUtils.KEY_d; +import static org.gradoop.common.GradoopTestUtils.KEY_e; +import static org.gradoop.common.GradoopTestUtils.KEY_f; +import static org.gradoop.common.GradoopTestUtils.LIST_VAL_a; +import static org.gradoop.common.GradoopTestUtils.LONG_VAL_3; +import static org.gradoop.common.GradoopTestUtils.MAP_VAL_9; +import static org.gradoop.common.GradoopTestUtils.NULL_VAL_0; +import static org.gradoop.common.GradoopTestUtils.SET_VAL_f; +import static org.gradoop.common.GradoopTestUtils.SHORT_VAL_e; +import static org.gradoop.common.GradoopTestUtils.STRING_VAL_6; +import static org.gradoop.common.GradoopTestUtils.SUPPORTED_PROPERTIES; +import static org.gradoop.common.GradoopTestUtils.TIME_VAL_c; +import static org.gradoop.common.GradoopTestUtils.validateEPGMElementCollections; +import static org.gradoop.common.GradoopTestUtils.validateEPGMElements; +import static org.gradoop.common.GradoopTestUtils.validateEPGMGraphElementCollections; +import static org.gradoop.common.GradoopTestUtils.validateEPGMGraphElements; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -68,8 +105,7 @@ public class StoreTest extends AccumuloStoreTestBase { @Test public void test01_writeCloseOpenReadTest() throws AccumuloSecurityException, AccumuloException, IOException { - GradoopAccumuloConfig config = - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST01); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(TEST01); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); @@ -101,8 +137,7 @@ public void test01_writeCloseOpenReadTest() throws AccumuloSecurityException, Ac @Test public void test02_writeFlushReadTest() throws AccumuloSecurityException, AccumuloException, IOException { - GradoopAccumuloConfig config = - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST02); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(TEST02); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); graphStore.setAutoFlush(false); @@ -135,8 +170,7 @@ public void test02_writeFlushReadTest() throws AccumuloSecurityException, Accumu @Test public void test03_iteratorTest() throws IOException, AccumuloSecurityException, AccumuloException { - GradoopAccumuloConfig config = - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST03); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(TEST03); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); Collection graphHeads = GradoopTestUtils.getSocialNetworkLoader().getGraphHeads(); @@ -174,16 +208,15 @@ public void test03_iteratorTest() throws IOException, AccumuloSecurityException, } /** - * Tries to add an unsupported property type {@link Set} as property value. + * Tries to add an unsupported property type {@link Queue} as property value. */ @Test(expected = UnsupportedTypeException.class) public void test04_wrongPropertyTypeTest() throws AccumuloSecurityException, AccumuloException { - GradoopAccumuloConfig config = - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST04); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(TEST04); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); - // Set is not supported by - final Set value = Sets.newHashSet(); + // Queue is not supported by + final Queue value = Queues.newPriorityQueue(); GradoopId vertexID = GradoopId.get(); final String label = "A"; @@ -192,7 +225,10 @@ public void test04_wrongPropertyTypeTest() throws AccumuloSecurityException, Acc final GradoopIdSet graphs = new GradoopIdSet(); - graphStore.writeVertex(config.getVertexFactory().initVertex(vertexID, label, props, graphs)); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + graphStore.writeVertex(flinkConfig + .getVertexFactory() + .initVertex(vertexID, label, props, graphs)); } /** @@ -202,8 +238,7 @@ public void test04_wrongPropertyTypeTest() throws AccumuloSecurityException, Acc @Test public void test05_propertyTypeTest() throws AccumuloSecurityException, AccumuloException, IOException { - GradoopAccumuloConfig config = - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST05); + GradoopAccumuloConfig config = AccumuloTestSuite.getAcConfig(TEST05); AccumuloEPGMStore graphStore = new AccumuloEPGMStore(config); final GradoopId vertexID = GradoopId.get(); @@ -214,7 +249,9 @@ public void test05_propertyTypeTest() throws AccumuloSecurityException, Accumulo final GradoopIdSet graphs = new GradoopIdSet(); // write to store - graphStore.writeVertex(config.getVertexFactory() + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + graphStore.writeVertex(flinkConfig + .getVertexFactory() .initVertex(vertexID, label, properties, graphs)); graphStore.flush(); @@ -283,6 +320,14 @@ public void test05_propertyTypeTest() throws AccumuloSecurityException, Accumulo assertTrue(v.getPropertyValue(propertyKey).isDateTime()); assertEquals(DATETIME_VAL_d, v.getPropertyValue(propertyKey).getDateTime()); break; + case KEY_e: + assertTrue(v.getPropertyValue(propertyKey).isShort()); + assertEquals(SHORT_VAL_e, v.getPropertyValue(propertyKey).getShort()); + break; + case KEY_f: + assertTrue(v.getPropertyValue(propertyKey).isSet()); + assertEquals(SET_VAL_f, v.getPropertyValue(propertyKey).getSet()); + break; } } } diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/IOBasicTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/IOBasicTest.java index 198a7345bcab..0216d2c13fd0 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/IOBasicTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/IOBasicTest.java @@ -17,18 +17,16 @@ import com.google.common.collect.Lists; import org.apache.flink.api.java.io.LocalCollectionOutputFormat; -import org.gradoop.storage.impl.accumulo.AccumuloTestSuite; import org.gradoop.common.GradoopTestUtils; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; import org.gradoop.flink.model.GradoopFlinkTestBase; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.util.FlinkAsciiGraphLoader; import org.gradoop.flink.util.GradoopFlinkConfig; -import org.gradoop.storage.impl.accumulo.io.AccumuloDataSink; -import org.gradoop.storage.impl.accumulo.io.AccumuloDataSource; +import org.gradoop.storage.impl.accumulo.AccumuloEPGMStore; +import org.gradoop.storage.impl.accumulo.AccumuloTestSuite; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -50,8 +48,7 @@ public class IOBasicTest extends GradoopFlinkTestBase { @Test public void test01_read() throws Exception { - AccumuloEPGMStore accumuloStore = new AccumuloEPGMStore( - AccumuloTestSuite.getAcConfig(getExecutionEnvironment(), TEST_01)); + AccumuloEPGMStore accumuloStore = new AccumuloEPGMStore(AccumuloTestSuite.getAcConfig(TEST_01)); Collection graphHeads = GradoopTestUtils.getSocialNetworkLoader().getGraphHeads(); Collection vertices = GradoopTestUtils.getSocialNetworkLoader().getVertices(); @@ -69,7 +66,9 @@ public void test01_read() throws Exception { } accumuloStore.flush(); - GraphCollection collection = new AccumuloDataSource(accumuloStore).getGraphCollection(); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + GraphCollection collection = new AccumuloDataSource(accumuloStore, flinkConfig) + .getGraphCollection(); Collection loadedGraphHeads = Lists.newArrayList(); Collection loadedVertices = Lists.newArrayList(); @@ -92,8 +91,7 @@ public void test01_read() throws Exception { @Test public void test02_write() throws Exception { - AccumuloEPGMStore accumuloStore = new AccumuloEPGMStore(AccumuloTestSuite - .getAcConfig(getExecutionEnvironment(), TEST_02)); + AccumuloEPGMStore accumuloStore = new AccumuloEPGMStore(AccumuloTestSuite.getAcConfig(TEST_02)); FlinkAsciiGraphLoader loader = new FlinkAsciiGraphLoader( GradoopFlinkConfig.createConfig(getExecutionEnvironment())); @@ -102,13 +100,14 @@ public void test02_write() throws Exception { GradoopTestUtils.SOCIAL_NETWORK_GDL_FILE); loader.initDatabaseFromStream(inputStream); - new AccumuloDataSink(accumuloStore).write(accumuloStore - .getConfig() - .getGraphCollectionFactory() - .fromCollections( - loader.getGraphHeads(), - loader.getVertices(), - loader.getEdges())); + + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + new AccumuloDataSink(accumuloStore, flinkConfig) + .write(flinkConfig.getGraphCollectionFactory() + .fromCollections( + loader.getGraphHeads(), + loader.getVertices(), + loader.getEdges())); getExecutionEnvironment().execute(); accumuloStore.flush(); diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOEdgePredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOEdgePredicateTest.java index fc6778cc7b00..ce6d1668cf2b 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOEdgePredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOEdgePredicateTest.java @@ -15,12 +15,13 @@ */ package org.gradoop.storage.impl.accumulo.io.source; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.common.GradoopTestUtils; import org.gradoop.common.model.impl.pojo.Edge; +import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.common.predicate.query.Query; -import org.gradoop.storage.utils.AccumuloFilters; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.impl.accumulo.io.AccumuloDataSource; +import org.gradoop.storage.utils.AccumuloFilters; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -38,7 +39,7 @@ public class IOEdgePredicateTest extends AccumuloStoreTestBase { @Test public void queryEdgeByProperty() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List storeEdges = loader.getEdges().stream() .filter(it -> { assert it.getProperties() != null; @@ -49,7 +50,9 @@ public void queryEdgeByProperty() throws Throwable { }) .collect(Collectors.toList()); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource( + store, + GradoopFlinkConfig.createConfig(getExecutionEnvironment())); List query = source.applyEdgePredicate( Query.elements() .fromAll() @@ -64,7 +67,7 @@ public void queryEdgeByProperty() throws Throwable { @Test public void findEdgeByLabelRegex() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { Pattern queryFormula = Pattern.compile("has.*+"); //edge label query @@ -73,7 +76,7 @@ public void findEdgeByLabelRegex() throws Throwable { .collect(Collectors.toList()); //edge label regex query - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List query = source.applyEdgePredicate( Query.elements() .fromAll() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOElementIdRangeTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOElementIdRangeTest.java index 9d9492dcd485..2d46a520739d 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOElementIdRangeTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOElementIdRangeTest.java @@ -15,13 +15,13 @@ */ package org.gradoop.storage.impl.accumulo.io.source; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.common.model.impl.id.GradoopIdSet; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.Element; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.storage.common.predicate.query.Query; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.impl.accumulo.io.AccumuloDataSource; import org.junit.Assert; import org.junit.FixMethodOrder; @@ -48,7 +48,7 @@ public class IOElementIdRangeTest extends AccumuloStoreTestBase { */ @Test public void test01_vertexIdSetQueryTest() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List inputVertices = sample(new ArrayList<>(loader.getVertices()), 5); //vertex id query @@ -56,7 +56,7 @@ public void test01_vertexIdSetQueryTest() throws Throwable { .map(Element::getId) .collect(Collectors.toList())); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); Assert.assertTrue(!source.isFilterPushedDown()); source = source.applyVertexPredicate( @@ -81,7 +81,7 @@ public void test01_vertexIdSetQueryTest() throws Throwable { */ @Test public void test02_edgeIdSetQueryTest() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { List inputEdges = sample(new ArrayList<>(loader.getEdges()), 5); //edge id query @@ -89,7 +89,7 @@ public void test02_edgeIdSetQueryTest() throws Throwable { .map(Element::getId) .collect(Collectors.toList())); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); Assert.assertTrue(!source.isFilterPushedDown()); source = source.applyEdgePredicate( @@ -114,7 +114,7 @@ public void test02_edgeIdSetQueryTest() throws Throwable { */ @Test public void test03_graphIdSetQueryTest() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { List inputGraphs = sample(new ArrayList<>(loader.getGraphHeads()), 3); //vertex id query @@ -122,7 +122,7 @@ public void test03_graphIdSetQueryTest() throws Throwable { .map(Element::getId) .collect(Collectors.toList())); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); Assert.assertTrue(!source.isFilterPushedDown()); source = source.applyGraphPredicate( diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOGraphPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOGraphPredicateTest.java index 80b518038220..b028ccbe145a 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOGraphPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOGraphPredicateTest.java @@ -15,12 +15,12 @@ */ package org.gradoop.storage.impl.accumulo.io.source; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.common.GradoopTestUtils; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.storage.common.predicate.query.Query; -import org.gradoop.storage.utils.AccumuloFilters; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.impl.accumulo.io.AccumuloDataSource; +import org.gradoop.storage.utils.AccumuloFilters; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -42,7 +42,7 @@ public class IOGraphPredicateTest extends AccumuloStoreTestBase { */ @Test public void test01_queryGraphByProperty() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List storeGraphs = loader.getGraphHeads().stream() .filter(it -> { assert it.getProperties() != null; @@ -53,7 +53,7 @@ public void test01_queryGraphByProperty() throws Throwable { }) .collect(Collectors.toList()); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List query = source.applyGraphPredicate( Query.elements() .fromAll() @@ -73,7 +73,7 @@ public void test01_queryGraphByProperty() throws Throwable { */ @Test public void test02_queryByMulti() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { List storeGraphs = loader.getGraphHeads().stream() .filter(it -> Objects.equals(it.getLabel(), "Community")) .filter(it -> it.getProperties() != null) @@ -82,7 +82,7 @@ public void test02_queryByMulti() throws Throwable { .filter(it -> it.getPropertyValue("vertexCount").getInt() < 4) .collect(Collectors.toList()); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List query = source.applyGraphPredicate( Query.elements() .fromAll() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOVertexPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOVertexPredicateTest.java index 989abb591f20..e6a99a3e56f7 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOVertexPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/io/source/IOVertexPredicateTest.java @@ -15,12 +15,12 @@ */ package org.gradoop.storage.impl.accumulo.io.source; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.storage.impl.accumulo.predicate.filter.api.AccumuloElementFilter; -import org.gradoop.storage.utils.AccumuloFilters; import org.gradoop.storage.common.predicate.query.Query; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.impl.accumulo.io.AccumuloDataSource; +import org.gradoop.storage.impl.accumulo.predicate.filter.api.AccumuloElementFilter; +import org.gradoop.storage.utils.AccumuloFilters; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -46,7 +46,7 @@ public class IOVertexPredicateTest extends AccumuloStoreTestBase { */ @Test public void test01_writeAndQueryVertexByName() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { //vertex label and property query List inputVertices = sample(loader.getVertices() .stream() @@ -66,7 +66,7 @@ public void test01_writeAndQueryVertexByName() throws Throwable { } AccumuloElementFilter whereCases = labelFilter.and(nameFilter); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List queryResult = source .applyVertexPredicate( Query.elements() @@ -87,7 +87,7 @@ public void test01_writeAndQueryVertexByName() throws Throwable { */ @Test public void test02_findPersonByAge() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { //vertex label and property query List inputVertices = loader.getVertices() .stream() @@ -97,7 +97,7 @@ public void test02_findPersonByAge() throws Throwable { .filter(it -> it.getProperties().get("age").getInt() >= 35) .collect(Collectors.toList()); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List queryResult = source .applyVertexPredicate( Query.elements() @@ -120,7 +120,7 @@ public void test02_findPersonByAge() throws Throwable { */ @Test public void test03_findPersonByAge() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { //vertex label and property query List inputVertices = loader.getVertices() .stream() @@ -130,7 +130,7 @@ public void test03_findPersonByAge() throws Throwable { .filter(it -> it.getProperties().get("age").getInt() < 35) .collect(Collectors.toList()); - AccumuloDataSource source = new AccumuloDataSource(store); + AccumuloDataSource source = new AccumuloDataSource(store, config); List queryResult = source .applyVertexPredicate( Query.elements() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreBasicPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreBasicPredicateTest.java index 91b8614855b5..c808d0dadcba 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreBasicPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreBasicPredicateTest.java @@ -23,7 +23,7 @@ import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.storage.common.predicate.query.ElementQuery; import org.gradoop.storage.impl.accumulo.predicate.filter.api.AccumuloElementFilter; -import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.OR; +import org.gradoop.storage.impl.accumulo.predicate.filter.calculate.Or; import org.gradoop.storage.utils.AccumuloFilters; import org.gradoop.storage.common.predicate.query.Query; import org.junit.FixMethodOrder; @@ -38,7 +38,7 @@ import static org.gradoop.common.GradoopTestUtils.validateEPGMElementCollections; /** - * accumulo graph store predicate test + * Accumulo graph store predicate test */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class StoreBasicPredicateTest extends AccumuloStoreTestBase { @@ -48,14 +48,13 @@ public class StoreBasicPredicateTest extends AccumuloStoreTestBase { private static final String TEST03 = "basic_predicate_03"; /** - * pick 3 person randomly - * then find vertex with label 'Person' and with same name (property) value + * Pick 3 person randomly then find vertex with label 'Person' and with same name (property) value * * @throws Throwable if error */ @Test public void test01_findPersonByName() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { //vertex label and property query List inputVertices = sample(loader.getVertices() .stream() @@ -76,7 +75,7 @@ public void test01_findPersonByName() throws Throwable { return (AccumuloElementFilter) AccumuloFilters .propEquals("name", name); }) - .reduce((a, b) -> OR.create(a, b)) + .reduce((a, b) -> Or.create(a, b)) .orElse(it -> false)) )) .readRemainsAndClose(); @@ -86,13 +85,13 @@ public void test01_findPersonByName() throws Throwable { } /** - * find all person who's age is not smaller than 35 + * Find all person who's age is not smaller than 35 * * @throws Throwable if error */ @Test public void test02_findPersonByAge() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { //vertex label and property query List inputVertices = loader.getVertices() .stream() @@ -113,13 +112,13 @@ public void test02_findPersonByAge() throws Throwable { } /** - * find graph by property equality within a certain sample id range + * Find graph by property equality within a certain sample id range * * @throws Throwable if error */ @Test public void test03_findGraphByIdsAndProperty() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { List samples = sample(new ArrayList<>(loader.getGraphHeads()), 3); GradoopIdSet sampleRange = GradoopIdSet.fromExisting(samples.stream() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreIdsPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreIdsPredicateTest.java index 5ea2e48983f1..cbb26eabd26f 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreIdsPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreIdsPredicateTest.java @@ -46,7 +46,7 @@ public class StoreIdsPredicateTest extends AccumuloStoreTestBase { */ @Test public void test01_vertexIdSetQueryTest() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List inputVertices = sample(new ArrayList<>(loader.getVertices()), 5); //vertex id query @@ -71,7 +71,7 @@ public void test01_vertexIdSetQueryTest() throws Throwable { */ @Test public void test02_edgeIdSetQueryTest() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { List inputEdges = sample(new ArrayList<>(loader.getEdges()), 5); //edge id query @@ -91,7 +91,7 @@ public void test02_edgeIdSetQueryTest() throws Throwable { @Test public void test03_graphIdSetQueryTest() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { List inputGraphs = sample(new ArrayList<>(loader.getGraphHeads()), 3); GradoopIdSet ids = GradoopIdSet.fromExisting(inputGraphs.stream() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreLabelPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreLabelPredicateTest.java index 4cc8c520d9c7..9033732f900e 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreLabelPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StoreLabelPredicateTest.java @@ -18,9 +18,9 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.storage.common.predicate.query.Query; import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.utils.AccumuloFilters; -import org.gradoop.storage.common.predicate.query.Query; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -49,7 +49,7 @@ public class StoreLabelPredicateTest extends AccumuloStoreTestBase { */ @Test public void test01_vertexLabelEquals() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List inputVertex = loader.getVertices().stream() .filter(it -> Objects.equals(it.getLabel(), "Person") || @@ -75,7 +75,7 @@ public void test01_vertexLabelEquals() throws Throwable { */ @Test public void test02_edgeLabelEquals() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { List inputEdges = loader.getEdges().stream() .filter(it -> Objects.equals(it.getLabel(), "hasInterest") || @@ -100,7 +100,7 @@ public void test02_edgeLabelEquals() throws Throwable { */ @Test public void test03_vertexLabelRegex() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { Pattern queryFormula = Pattern.compile("[Pers|Ta].*+"); List inputVertex = loader.getVertices().stream() @@ -126,7 +126,7 @@ public void test03_vertexLabelRegex() throws Throwable { */ @Test public void test04_edgeLabelRegex() throws Throwable { - doTest(TEST04, (loader, store) -> { + doTest(TEST04, (loader, store, config) -> { Pattern queryFormula = Pattern.compile("has.*+"); //graph label query @@ -151,7 +151,7 @@ public void test04_edgeLabelRegex() throws Throwable { */ @Test public void test05_graphLabelEquals() throws Throwable { - doTest(TEST05, (loader, store) -> { + doTest(TEST05, (loader, store, config) -> { List inputGraph = loader.getGraphHeads().stream() .filter(it -> Objects.equals(it.getLabel(), "Community") || Objects.equals(it.getLabel(), "Person")) @@ -173,7 +173,7 @@ public void test05_graphLabelEquals() throws Throwable { */ @Test public void test06_graphLabelRegex() throws Throwable { - doTest(TEST06, (loader, store) -> { + doTest(TEST06, (loader, store, config) -> { Pattern queryFormula = Pattern.compile("Com.*+"); List inputGraph = loader.getGraphHeads().stream() diff --git a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StorePropPredicateTest.java b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StorePropPredicateTest.java index 278d2e6f3dd1..ee24a352f942 100644 --- a/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StorePropPredicateTest.java +++ b/gradoop-store/gradoop-accumulo/src/test/java/org/gradoop/storage/impl/accumulo/predicate/StorePropPredicateTest.java @@ -15,12 +15,12 @@ */ package org.gradoop.storage.impl.accumulo.predicate; -import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.common.GradoopTestUtils; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.storage.common.predicate.query.Query; +import org.gradoop.storage.impl.accumulo.AccumuloStoreTestBase; import org.gradoop.storage.utils.AccumuloFilters; import org.junit.FixMethodOrder; import org.junit.Test; @@ -50,7 +50,7 @@ public class StorePropPredicateTest extends AccumuloStoreTestBase { */ @Test public void test01_vertexPropEquals() throws Throwable { - doTest(TEST01, (loader, store) -> { + doTest(TEST01, (loader, store, config) -> { List inputVertices = loader.getVertices().stream() .filter(it -> { assert it.getProperties() != null; @@ -79,7 +79,7 @@ public void test01_vertexPropEquals() throws Throwable { */ @Test public void test02_edgePropEquals() throws Throwable { - doTest(TEST02, (loader, store) -> { + doTest(TEST02, (loader, store, config) -> { List inputVertices = loader.getEdges().stream() .filter(it -> { assert it.getProperties() != null; @@ -108,7 +108,7 @@ public void test02_edgePropEquals() throws Throwable { */ @Test public void test03_propRegex() throws Throwable { - doTest(TEST03, (loader, store) -> { + doTest(TEST03, (loader, store, config) -> { Pattern queryFormula = Pattern.compile("(Leipzig|Dresden)"); List inputVertices = loader.getVertices().stream() @@ -140,7 +140,7 @@ public void test03_propRegex() throws Throwable { */ @Test public void test04_propLargerThan() throws Throwable { - doTest(TEST04, (loader, store) -> { + doTest(TEST04, (loader, store, config) -> { List inputVertices = loader.getEdges().stream() .filter(it -> { assert it.getProperties() != null; @@ -171,7 +171,7 @@ public void test04_propLargerThan() throws Throwable { */ @Test public void test05_propSmallerThan() throws Throwable { - doTest(TEST05, (loader, store) -> { + doTest(TEST05, (loader, store, config) -> { List inputVertices = loader.getGraphHeads() .stream() .filter(it -> it.getPropertyValue("vertexCount") != null) diff --git a/gradoop-store/gradoop-hbase/pom.xml b/gradoop-store/gradoop-hbase/pom.xml index 61af2f242bf7..994084e5417a 100644 --- a/gradoop-store/gradoop-hbase/pom.xml +++ b/gradoop-store/gradoop-hbase/pom.xml @@ -5,7 +5,7 @@ gradoop-store org.gradoop - 0.5.0-SNAPSHOT + 0.4.1 gradoop-hbase @@ -117,6 +117,10 @@ + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/config/GradoopHBaseConfig.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/config/GradoopHBaseConfig.java index 1368b508df30..eaea943a25b9 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/config/GradoopHBaseConfig.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/config/GradoopHBaseConfig.java @@ -16,7 +16,6 @@ package org.gradoop.storage.config; import org.apache.commons.lang.StringUtils; -import org.apache.flink.api.java.ExecutionEnvironment; import org.apache.hadoop.hbase.TableName; import org.gradoop.common.model.impl.pojo.EdgeFactory; import org.gradoop.common.model.impl.pojo.GraphHeadFactory; @@ -36,31 +35,38 @@ /** * Configuration class for using HBase with Gradoop. */ -public class GradoopHBaseConfig - extends GradoopStoreConfig { +public class GradoopHBaseConfig implements GradoopStoreConfig { + + /** + * Definition for serialize version control + */ + private static final int serialVersionUID = 23; /** * Graph table name. */ - private final TableName graphTableName; + private final String graphTableName; + /** * EPGMVertex table name. */ - private final TableName vertexTableName; + private final String vertexTableName; /** * EPGMEdge table name. */ - private final TableName edgeTableName; + private final String edgeTableName; /** * Graph head handler. */ private final GraphHeadHandler graphHeadHandler; + /** * EPGMVertex handler. */ private final VertexHandler vertexHandler; + /** * EPGMEdge handler. */ @@ -72,7 +78,6 @@ public class GradoopHBaseConfig * @param graphHeadHandler graph head handler * @param vertexHandler vertex handler * @param edgeHandler edge handler - * @param env flink execution environment * @param graphTableName graph table name * @param vertexTableName vertex table name * @param edgeTableName edge table name @@ -81,12 +86,10 @@ private GradoopHBaseConfig( GraphHeadHandler graphHeadHandler, VertexHandler vertexHandler, EdgeHandler edgeHandler, - ExecutionEnvironment env, String graphTableName, String vertexTableName, String edgeTableName ) { - super(new GraphHeadFactory(), new VertexFactory(), new EdgeFactory(), env); checkArgument(!StringUtils.isEmpty(graphTableName), "Graph table name was null or empty"); checkArgument(!StringUtils.isEmpty(vertexTableName), @@ -94,9 +97,9 @@ private GradoopHBaseConfig( checkArgument(!StringUtils.isEmpty(edgeTableName), "EPGMEdge table name was null or empty"); - this.graphTableName = TableName.valueOf(graphTableName); - this.vertexTableName = TableName.valueOf(vertexTableName); - this.edgeTableName = TableName.valueOf(edgeTableName); + this.graphTableName = graphTableName; + this.vertexTableName = vertexTableName; + this.edgeTableName = edgeTableName; this.graphHeadHandler = checkNotNull(graphHeadHandler, "GraphHeadHandler was null"); this.vertexHandler = checkNotNull(vertexHandler, "VertexHandler was null"); @@ -120,7 +123,6 @@ private GradoopHBaseConfig( this(config.getGraphHeadHandler(), config.getVertexHandler(), config.getEdgeHandler(), - config.getExecutionEnvironment(), graphTableName, vertexTableName, edgeTableName); @@ -130,10 +132,9 @@ private GradoopHBaseConfig( * Creates a default Configuration using POJO handlers for vertices, edges * and graph heads and default table names. * - * @param env apache flink execution environment * @return Default Gradoop HBase configuration. */ - public static GradoopHBaseConfig getDefaultConfig(ExecutionEnvironment env) { + public static GradoopHBaseConfig getDefaultConfig() { GraphHeadHandler graphHeadHandler = new HBaseGraphHeadHandler(new GraphHeadFactory()); VertexHandler vertexHandler = new HBaseVertexHandler(new VertexFactory()); EdgeHandler edgeHandler = new HBaseEdgeHandler(new EdgeFactory()); @@ -142,7 +143,6 @@ public static GradoopHBaseConfig getDefaultConfig(ExecutionEnvironment env) { graphHeadHandler, vertexHandler, edgeHandler, - env, HBaseConstants.DEFAULT_TABLE_GRAPHS, HBaseConstants.DEFAULT_TABLE_VERTICES, HBaseConstants.DEFAULT_TABLE_EDGES @@ -168,26 +168,56 @@ public static GradoopHBaseConfig createConfig( return new GradoopHBaseConfig(gradoopConfig, graphTableName, vertexTableName, edgeTableName); } + /** + * Get vertex table name + * + * @return vertex table name + */ public TableName getVertexTableName() { - return vertexTableName; + return TableName.valueOf(vertexTableName); } + /** + * Get edge table name + * + * @return edge table name + */ public TableName getEdgeTableName() { - return edgeTableName; + return TableName.valueOf(edgeTableName); } + /** + * Get graph table name + * + * @return graph table name + */ public TableName getGraphTableName() { - return graphTableName; + return TableName.valueOf(graphTableName); } + /** + * Get graph head handler + * + * @return graph head handler + */ public GraphHeadHandler getGraphHeadHandler() { return graphHeadHandler; } + /** + * Get vertex handler + * + * @return vertex handler + */ public VertexHandler getVertexHandler() { return vertexHandler; } + /** + * Get edge handler + * + * @return edge handler + */ public EdgeHandler getEdgeHandler() { return edgeHandler; } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/HBaseEPGMStore.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/HBaseEPGMStore.java index ac6d4e1ee2ba..80c87eac2fa1 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/HBaseEPGMStore.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/HBaseEPGMStore.java @@ -40,8 +40,8 @@ import org.gradoop.storage.impl.hbase.api.EdgeHandler; import org.gradoop.storage.impl.hbase.api.GraphHeadHandler; import org.gradoop.storage.impl.hbase.api.VertexHandler; -import org.gradoop.storage.impl.hbase.filter.HBaseFilterUtils; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import org.gradoop.storage.impl.hbase.iterator.HBaseEdgeIterator; import org.gradoop.storage.impl.hbase.iterator.HBaseGraphIterator; import org.gradoop.storage.impl.hbase.iterator.HBaseVertexIterator; @@ -346,7 +346,7 @@ private void attachFilter( } if (query.getFilterPredicate() != null) { - conjunctFilters.addFilter(query.getFilterPredicate().toHBaseFilter()); + conjunctFilters.addFilter(query.getFilterPredicate().toHBaseFilter(false)); } // if there are filters inside the root list, add it to the Scan object diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/EdgeHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/EdgeHandler.java index 0faedca7069d..5ab280c594d4 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/EdgeHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/EdgeHandler.java @@ -21,9 +21,7 @@ import org.gradoop.common.model.impl.id.GradoopId; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.storage.common.predicate.query.ElementQuery; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; - -import java.io.IOException; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; /** * Responsible for reading and writing edge data from and to HBase. @@ -70,18 +68,16 @@ public interface EdgeHandler extends GraphElementHandler { * @param put {@link} Put to add edge to * @param edgeData edge data to be written * @return put with edge data - * @throws IOException if writing the {@link EPGMEdge} to store fails */ - Put writeEdge(final Put put, final EPGMEdge edgeData) throws IOException; + Put writeEdge(final Put put, final EPGMEdge edgeData); /** * Reads the edge data from the given {@link Result}. * * @param res HBase row * @return edge data contained in the given result - * @throws IOException if reading the result as {@link Edge} instance fails */ - Edge readEdge(final Result res) throws IOException; + Edge readEdge(final Result res); /** * Applies the given ElementQuery to the handler. diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/ElementHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/ElementHandler.java index d1028380d39a..0156d13bd11a 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/ElementHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/ElementHandler.java @@ -69,11 +69,7 @@ Put writeLabel( * @param property property * @return put with property */ - Put writeProperty( - final Put put, - final Property property - ) throws - IOException; + Put writeProperty(final Put put, final Property property); /** * Adds all properties of the given element to the given {@link Put} and @@ -83,11 +79,7 @@ Put writeProperty( * @param entity entity to use properties from * @return put with properties */ - Put writeProperties( - final Put put, - final EPGMElement entity - ) throws - IOException; + Put writeProperties(final Put put, final EPGMElement entity); /** * Reads the label from the given row {@link Result}. @@ -102,9 +94,8 @@ Put writeProperties( * * @param res row result * @return all properties contained in the row - * @throws IOException if reading result to Properties failed */ - Properties readProperties(final Result res) throws IOException; + Properties readProperties(final Result res); /** * Creates table based on the given table descriptor. diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/GraphHeadHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/GraphHeadHandler.java index 5f8742e79a3a..5cf09721bd69 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/GraphHeadHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/GraphHeadHandler.java @@ -19,11 +19,9 @@ import org.apache.hadoop.hbase.client.Result; import org.gradoop.common.model.api.entities.EPGMGraphHead; import org.gradoop.common.model.impl.pojo.GraphHead; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import org.gradoop.storage.common.predicate.query.ElementQuery; -import java.io.IOException; - /** * This class is responsible for reading and writing EPGM graph heads from * and to HBase. @@ -36,18 +34,16 @@ public interface GraphHeadHandler extends ElementHandler { * @param put put to add graph data to * @param graphData graph data * @return put with graph data - * @throws IOException if writing the {@link EPGMGraphHead} to store fails */ - Put writeGraphHead(final Put put, final EPGMGraphHead graphData) throws IOException; + Put writeGraphHead(final Put put, final EPGMGraphHead graphData); /** * Reads the graph data from the given result. * * @param res HBase row * @return graph entity - * @throws IOException if reading the result as {@link GraphHead} instance fails */ - GraphHead readGraphHead(final Result res) throws IOException; + GraphHead readGraphHead(final Result res); /** * Applies the given ElementQuery to the handler. diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/VertexHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/VertexHandler.java index a5cbc1f95816..42cb4ace7918 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/VertexHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/api/VertexHandler.java @@ -19,11 +19,9 @@ import org.apache.hadoop.hbase.client.Result; import org.gradoop.common.model.api.entities.EPGMVertex; import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import org.gradoop.storage.common.predicate.query.ElementQuery; -import java.io.IOException; - /** * Responsible for reading and writing vertex data from and to HBase. */ @@ -35,18 +33,16 @@ public interface VertexHandler extends GraphElementHandler { * @param put {@link Put} to add vertex to * @param vertexData vertex data to be written * @return put with vertex data - * @throws IOException on writing failure */ - Put writeVertex(final Put put, final EPGMVertex vertexData) throws IOException; + Put writeVertex(final Put put, final EPGMVertex vertexData); /** * Reads the vertex data from the given {@link Result}. * * @param res HBase row * @return vertex data contained in the given result. - * @throws IOException if reading the result as {@link Vertex} instance fails */ - Vertex readVertex(final Result res) throws IOException; + Vertex readVertex(final Result res); /** * Applies the given ElementQuery to the handler. diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/constants/HBaseConstants.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/constants/HBaseConstants.java index b32e2cc9ba93..9f85c1e6c34f 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/constants/HBaseConstants.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/constants/HBaseConstants.java @@ -45,9 +45,13 @@ public final class HBaseConstants { */ public static final String COL_GRAPHS = "g"; /** - * Column family name for properties. + * Column family name for property type. */ - public static final String CF_PROPERTIES = "p"; + public static final String CF_PROPERTY_TYPE = "p_type"; + /** + * Column family name for property value. + */ + public static final String CF_PROPERTY_VALUE = "p_value"; /** * Column identifier for source vertex identifier. */ diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/HBaseFilterUtils.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/HBaseFilterUtils.java deleted file mode 100644 index 4078f0d1552f..000000000000 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/HBaseFilterUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.hbase.filter; - -import org.apache.hadoop.hbase.filter.BinaryComparator; -import org.apache.hadoop.hbase.filter.CompareFilter; -import org.apache.hadoop.hbase.filter.Filter; -import org.apache.hadoop.hbase.filter.FilterList; -import org.apache.hadoop.hbase.filter.RowFilter; -import org.gradoop.common.model.impl.id.GradoopId; -import org.gradoop.common.model.impl.id.GradoopIdSet; - -/** - * Utility class for common HBase filter tasks - */ -public class HBaseFilterUtils { - - /** - * Creates a HBase Filter object to return only graph elements that are equal to the given - * GradoopIds. - * - * @param elementIds a set of graph element GradoopIds to filter - * @return a HBase Filter object - */ - public static Filter getIdFilter(GradoopIdSet elementIds) { - FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); - - for (GradoopId gradoopId : elementIds) { - RowFilter rowFilter = new RowFilter( - CompareFilter.CompareOp.EQUAL, - new BinaryComparator(gradoopId.toByteArray()) - ); - filterList.addFilter(rowFilter); - } - return filterList; - } -} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseEdgeHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseEdgeHandler.java index 36a1ae8880eb..0aa3c398e6a1 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseEdgeHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseEdgeHandler.java @@ -28,7 +28,7 @@ import org.gradoop.storage.common.predicate.query.ElementQuery; import org.gradoop.storage.impl.hbase.api.EdgeHandler; import org.gradoop.storage.impl.hbase.constants.HBaseConstants; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import java.io.IOException; @@ -87,7 +87,8 @@ public HBaseEdgeHandler(EPGMEdgeFactory edgeFactory) { public void createTable(final Admin admin, final HTableDescriptor tableDescriptor) throws IOException { tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_META)); - tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTIES)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_TYPE)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_VALUE)); admin.createTable(tableDescriptor); } @@ -127,7 +128,7 @@ public GradoopId readTargetId(Result res) { * {@inheritDoc} */ @Override - public Put writeEdge(Put put, EPGMEdge edgeData) throws IOException { + public Put writeEdge(Put put, EPGMEdge edgeData) { writeLabel(put, edgeData); writeSource(put, edgeData.getSourceId()); writeTarget(put, edgeData.getTargetId()); @@ -140,9 +141,8 @@ public Put writeEdge(Put put, EPGMEdge edgeData) throws IOException { * {@inheritDoc} */ @Override - public Edge readEdge(Result res) throws IOException { - return edgeFactory - .initEdge(readId(res), readLabel(res), readSourceId(res), readTargetId(res), + public Edge readEdge(Result res) { + return edgeFactory.initEdge(readId(res), readLabel(res), readSourceId(res), readTargetId(res), readProperties(res), readGraphIds(res)); } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseElementHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseElementHandler.java index 791f5f72e0a5..da413086622c 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseElementHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseElementHandler.java @@ -18,15 +18,13 @@ import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Writables; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.common.model.impl.id.GradoopId; import org.gradoop.common.model.impl.properties.Properties; import org.gradoop.common.model.impl.properties.Property; -import org.gradoop.common.model.impl.properties.PropertyValue; +import org.gradoop.common.model.impl.properties.PropertyValueUtils; import org.gradoop.storage.impl.hbase.api.ElementHandler; import org.gradoop.storage.impl.hbase.constants.HBaseConstants; -import org.gradoop.storage.impl.hbase.iterator.HBasePropertyValueWrapper; import java.io.IOException; import java.util.Map; @@ -47,9 +45,16 @@ public abstract class HBaseElementHandler implements ElementHandler { private static final byte[] COL_LABEL_BYTES = Bytes.toBytes(HBaseConstants.COL_LABEL); /** - * Byte representation of the properties column family. + * Byte representation of the property type column family. */ - private static final byte[] CF_PROPERTIES_BYTES = Bytes.toBytes(HBaseConstants.CF_PROPERTIES); + private static final byte[] CF_PROPERTY_TYPE_BYTES = + Bytes.toBytes(HBaseConstants.CF_PROPERTY_TYPE); + + /** + * Byte representation of the property value column family. + */ + private static final byte[] CF_PROPERTY_VALUE_BYTES = + Bytes.toBytes(HBaseConstants.CF_PROPERTY_VALUE); /** * {@inheritDoc} @@ -83,14 +88,11 @@ public Put writeLabel(final Put put, final EPGMElement entity) { * {@inheritDoc} */ @Override - public Put writeProperty(final Put put, Property property) throws IOException { - HBasePropertyValueWrapper wrapper = new HBasePropertyValueWrapper(property.getValue()); - put.addColumn( - CF_PROPERTIES_BYTES, - Bytes.toBytes(property.getKey()), - Writables.getBytes(wrapper) - ); - + public Put writeProperty(final Put put, Property property) { + byte[] type = PropertyValueUtils.Bytes.getTypeByte(property.getValue()); + byte[] bytesWithoutType = PropertyValueUtils.Bytes.getRawBytesWithoutType(property.getValue()); + put.addColumn(CF_PROPERTY_TYPE_BYTES, Bytes.toBytes(property.getKey()), type); + put.addColumn(CF_PROPERTY_VALUE_BYTES, Bytes.toBytes(property.getKey()), bytesWithoutType); return put; } @@ -98,7 +100,7 @@ public Put writeProperty(final Put put, Property property) throws IOException { * {@inheritDoc} */ @Override - public Put writeProperties(final Put put, final EPGMElement entity) throws IOException { + public Put writeProperties(final Put put, final EPGMElement entity) { if (entity.getProperties() != null && entity.getPropertyCount() > 0) { for (Property property : entity.getProperties()) { writeProperty(put, property); @@ -119,42 +121,25 @@ public String readLabel(final Result res) { * {@inheritDoc} */ @Override - public Properties readProperties(final Result res) throws IOException { + public Properties readProperties(final Result res) { Properties properties = Properties.create(); - Map familyMap = res.getFamilyMap(CF_PROPERTIES_BYTES); - for (Map.Entry propertyColumn : familyMap.entrySet()) { + // Get Map which is Map + Map typeFamilyMap = res.getFamilyMap(CF_PROPERTY_TYPE_BYTES); + // Get Map which is Map + Map valueFamilyMap = res.getFamilyMap(CF_PROPERTY_VALUE_BYTES); + + for (Map.Entry propertyColumn : typeFamilyMap.entrySet()) { properties.set( - readPropertyKey(propertyColumn.getKey()), - readPropertyValue(propertyColumn.getValue())); + Bytes.toString(propertyColumn.getKey()), + PropertyValueUtils.Bytes.createFromTypeValueBytes( + propertyColumn.getValue(), + valueFamilyMap.get(propertyColumn.getKey()))); } return properties; } - /** - * Reads the property key from the given byte array. - * - * @param encKey encoded property key - * @return property key - */ - protected String readPropertyKey(final byte[] encKey) { - return Bytes.toString(encKey); - } - - /** - * Decodes a value from a given byte array. - * - * @param encValue encoded property value - * @return property value - */ - protected PropertyValue readPropertyValue(final byte[] encValue) throws IOException { - PropertyValue value = new PropertyValue(); - HBasePropertyValueWrapper wrapper = new HBasePropertyValueWrapper(value); - Writables.getWritable(encValue, wrapper); - return value; - } - /** * Deserializes a gradoop id from HBase row key. * diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphElementHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphElementHandler.java index b198dfbb78e8..bdce62596136 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphElementHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphElementHandler.java @@ -23,8 +23,6 @@ import org.gradoop.storage.impl.hbase.api.GraphElementHandler; import org.gradoop.storage.impl.hbase.constants.HBaseConstants; -import java.io.IOException; - /** * Handler class for entities that are contained in logical graphs (i.e., * vertex and edge data). @@ -41,7 +39,7 @@ public abstract class HBaseGraphElementHandler extends * {@inheritDoc} */ @Override - public Put writeGraphIds(Put put, EPGMGraphElement graphElement) throws IOException { + public Put writeGraphIds(Put put, EPGMGraphElement graphElement) { if (graphElement.getGraphCount() > 0) { put = put.addColumn( CF_META_BYTES, diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphHeadHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphHeadHandler.java index 0d015e7f277d..78c7329eb3da 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphHeadHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseGraphHeadHandler.java @@ -26,7 +26,7 @@ import org.gradoop.storage.common.predicate.query.ElementQuery; import org.gradoop.storage.impl.hbase.api.GraphHeadHandler; import org.gradoop.storage.impl.hbase.constants.HBaseConstants; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import java.io.IOException; @@ -76,7 +76,8 @@ public HBaseGraphHeadHandler(EPGMGraphHeadFactory graphHeadFactory) { public void createTable(final Admin admin, final HTableDescriptor tableDescriptor) throws IOException { tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_META)); - tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTIES)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_TYPE)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_VALUE)); admin.createTable(tableDescriptor); } @@ -84,7 +85,7 @@ public void createTable(final Admin admin, final HTableDescriptor tableDescripto * {@inheritDoc} */ @Override - public Put writeGraphHead(final Put put, final EPGMGraphHead graphData) throws IOException { + public Put writeGraphHead(final Put put, final EPGMGraphHead graphData) { writeLabel(put, graphData); writeProperties(put, graphData); return put; @@ -94,9 +95,8 @@ public Put writeGraphHead(final Put put, final EPGMGraphHead graphData) throws I * {@inheritDoc} */ @Override - public GraphHead readGraphHead(final Result res) throws IOException { - return graphHeadFactory - .initGraphHead(readId(res), readLabel(res), readProperties(res)); + public GraphHead readGraphHead(final Result res) { + return graphHeadFactory.initGraphHead(readId(res), readLabel(res), readProperties(res)); } /** diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseVertexHandler.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseVertexHandler.java index beaf3233bbe2..3b77ba383698 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseVertexHandler.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/handler/HBaseVertexHandler.java @@ -26,7 +26,7 @@ import org.gradoop.storage.common.predicate.query.ElementQuery; import org.gradoop.storage.impl.hbase.api.VertexHandler; import org.gradoop.storage.impl.hbase.constants.HBaseConstants; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import java.io.IOException; @@ -76,7 +76,8 @@ public HBaseVertexHandler(EPGMVertexFactory vertexFactory) { public void createTable(final Admin admin, final HTableDescriptor tableDescriptor) throws IOException { tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_META)); - tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTIES)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_TYPE)); + tableDescriptor.addFamily(new HColumnDescriptor(HBaseConstants.CF_PROPERTY_VALUE)); admin.createTable(tableDescriptor); } @@ -84,7 +85,7 @@ public void createTable(final Admin admin, final HTableDescriptor tableDescripto * {@inheritDoc} */ @Override - public Put writeVertex(Put put, EPGMVertex vertexData) throws IOException { + public Put writeVertex(Put put, EPGMVertex vertexData) { writeLabel(put, vertexData); writeProperties(put, vertexData); writeGraphIds(put, vertexData); @@ -95,7 +96,7 @@ public Put writeVertex(Put put, EPGMVertex vertexData) throws IOException { * {@inheritDoc} */ @Override - public Vertex readVertex(final Result res) throws IOException { + public Vertex readVertex(final Result res) { return vertexFactory.initVertex(readId(res), readLabel(res), readProperties(res), readGraphIds(res)); } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseBase.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseBase.java index a2c3ea5abcd5..ead587621500 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseBase.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseBase.java @@ -15,9 +15,12 @@ */ package org.gradoop.storage.impl.hbase.io; +import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.config.GradoopHBaseConfig; import org.gradoop.storage.impl.hbase.HBaseEPGMStore; +import javax.annotation.Nonnull; + /** * Base class for HBase data source and sink. */ @@ -27,13 +30,23 @@ abstract class HBaseBase { */ private final HBaseEPGMStore epgmStore; + /** + * Gradoop flink configuration + */ + private final GradoopFlinkConfig flinkConfig; + /** * Creates a new HBase data source/sink. * + * @param flinkConfig gradoop flink execute config * @param epgmStore store implementation */ - HBaseBase(HBaseEPGMStore epgmStore) { + HBaseBase( + @Nonnull HBaseEPGMStore epgmStore, + @Nonnull GradoopFlinkConfig flinkConfig + ) { this.epgmStore = epgmStore; + this.flinkConfig = flinkConfig; } HBaseEPGMStore getStore() { @@ -43,4 +56,9 @@ HBaseEPGMStore getStore() { GradoopHBaseConfig getHBaseConfig() { return epgmStore.getConfig(); } + + GradoopFlinkConfig getFlinkConfig() { + return flinkConfig; + } + } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSink.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSink.java index d33c59b0afe7..bab1c7431ff9 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSink.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSink.java @@ -22,11 +22,13 @@ import org.gradoop.flink.io.api.DataSink; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.LogicalGraph; +import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.impl.hbase.HBaseEPGMStore; import org.gradoop.storage.impl.hbase.io.functions.BuildEdgeMutation; import org.gradoop.storage.impl.hbase.io.functions.BuildGraphHeadMutation; import org.gradoop.storage.impl.hbase.io.functions.BuildVertexMutation; +import javax.annotation.Nonnull; import java.io.IOException; /** @@ -39,9 +41,13 @@ public class HBaseDataSink extends HBaseBase implements DataSink { * Creates a new HBase data sink. * * @param epgmStore store implementation + * @param flinkConfig gradoop flink execute config */ - public HBaseDataSink(HBaseEPGMStore epgmStore) { - super(epgmStore); + public HBaseDataSink( + @Nonnull HBaseEPGMStore epgmStore, + @Nonnull GradoopFlinkConfig flinkConfig + ) { + super(epgmStore, flinkConfig); } /** @@ -65,7 +71,7 @@ public void write(GraphCollection graphCollection) throws IOException { */ @Override public void write(LogicalGraph logicalGraph, boolean overwrite) throws IOException { - write(getHBaseConfig().getGraphCollectionFactory().fromGraph(logicalGraph), overwrite); + write(getFlinkConfig().getGraphCollectionFactory().fromGraph(logicalGraph), overwrite); } /** diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSource.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSource.java index 42802b669445..250597c65f74 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSource.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/HBaseDataSource.java @@ -18,21 +18,21 @@ import org.apache.flink.api.java.DataSet; import org.apache.flink.api.java.typeutils.TupleTypeInfo; import org.apache.flink.api.java.typeutils.TypeExtractor; -import org.gradoop.storage.config.GradoopHBaseConfig; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; -import org.gradoop.storage.impl.hbase.HBaseEPGMStore; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; -import org.gradoop.storage.common.predicate.query.ElementQuery; -import org.gradoop.storage.common.io.FilterableDataSource; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.model.api.epgm.LogicalGraph; import org.gradoop.flink.model.impl.functions.tuple.ValueOf1; import org.gradoop.flink.model.impl.operators.combination.ReduceCombination; +import org.gradoop.flink.util.GradoopFlinkConfig; +import org.gradoop.storage.common.io.FilterableDataSource; +import org.gradoop.storage.common.predicate.query.ElementQuery; +import org.gradoop.storage.impl.hbase.HBaseEPGMStore; import org.gradoop.storage.impl.hbase.io.inputformats.EdgeTableInputFormat; import org.gradoop.storage.impl.hbase.io.inputformats.GraphHeadTableInputFormat; import org.gradoop.storage.impl.hbase.io.inputformats.VertexTableInputFormat; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -67,28 +67,32 @@ public class HBaseDataSource extends HBaseBase * Creates a new HBase data source. * * @param epgmStore HBase store + * @param flinkConfig gradoop flink execute config */ public HBaseDataSource( - @Nonnull HBaseEPGMStore epgmStore + @Nonnull HBaseEPGMStore epgmStore, + @Nonnull GradoopFlinkConfig flinkConfig ) { - this(epgmStore, null, null, null); + this(epgmStore, flinkConfig, null, null, null); } /** * Private constructor to create a data source instance with predicates. * * @param epgmStore HBase store + * @param flinkConfig gradoop flink execute config * @param graphHeadQuery A predicate to apply to graph head elements * @param vertexQuery A predicate to apply to vertices * @param edgeQuery A predicate to apply to edges */ private HBaseDataSource( @Nonnull HBaseEPGMStore epgmStore, + @Nonnull GradoopFlinkConfig flinkConfig, @Nullable ElementQuery> graphHeadQuery, @Nullable ElementQuery> vertexQuery, @Nullable ElementQuery> edgeQuery ) { - super(epgmStore); + super(epgmStore, flinkConfig); this.graphHeadQuery = graphHeadQuery; this.vertexQuery = vertexQuery; this.edgeQuery = edgeQuery; @@ -107,27 +111,27 @@ public LogicalGraph getLogicalGraph() { */ @Override public GraphCollection getGraphCollection() { - GradoopHBaseConfig config = getHBaseConfig(); + GradoopFlinkConfig config = getFlinkConfig(); HBaseEPGMStore store = getStore(); DataSet graphHeads = config.getExecutionEnvironment() .createInput(new GraphHeadTableInputFormat( - config.getGraphHeadHandler().applyQuery(graphHeadQuery), - store.getGraphHeadName()), + getHBaseConfig().getGraphHeadHandler().applyQuery(graphHeadQuery), + store.getGraphHeadName()), new TupleTypeInfo<>(TypeExtractor.createTypeInfo(config.getGraphHeadFactory().getType()))) .map(new ValueOf1<>()); DataSet vertices = config.getExecutionEnvironment() .createInput(new VertexTableInputFormat( - config.getVertexHandler().applyQuery(vertexQuery), - store.getVertexTableName()), + getHBaseConfig().getVertexHandler().applyQuery(vertexQuery), + store.getVertexTableName()), new TupleTypeInfo<>(TypeExtractor.createTypeInfo(config.getVertexFactory().getType()))) .map(new ValueOf1<>()); DataSet edges = config.getExecutionEnvironment() .createInput(new EdgeTableInputFormat( - config.getEdgeHandler().applyQuery(edgeQuery), - store.getEdgeTableName()), + getHBaseConfig().getEdgeHandler().applyQuery(edgeQuery), + store.getEdgeTableName()), new TupleTypeInfo<>(TypeExtractor.createTypeInfo(config.getEdgeFactory().getType()))) .map(new ValueOf1<>()); @@ -140,8 +144,9 @@ public GraphCollection getGraphCollection() { @Nonnull @Override public HBaseDataSource applyGraphPredicate( - @Nonnull ElementQuery> query) { - return new HBaseDataSource(getStore(), query, vertexQuery, edgeQuery); + @Nonnull ElementQuery> query + ) { + return new HBaseDataSource(getStore(), getFlinkConfig(), query, vertexQuery, edgeQuery); } /** @@ -150,8 +155,9 @@ public HBaseDataSource applyGraphPredicate( @Nonnull @Override public HBaseDataSource applyVertexPredicate( - @Nonnull ElementQuery> query) { - return new HBaseDataSource(getStore(), graphHeadQuery, query, edgeQuery); + @Nonnull ElementQuery> query + ) { + return new HBaseDataSource(getStore(), getFlinkConfig(), graphHeadQuery, query, edgeQuery); } /** @@ -160,8 +166,9 @@ public HBaseDataSource applyVertexPredicate( @Nonnull @Override public HBaseDataSource applyEdgePredicate( - @Nonnull ElementQuery> query) { - return new HBaseDataSource(getStore(), graphHeadQuery, vertexQuery, query); + @Nonnull ElementQuery> query + ) { + return new HBaseDataSource(getStore(), getFlinkConfig(), graphHeadQuery, vertexQuery, query); } /** diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/BaseTableInputFormat.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/BaseTableInputFormat.java index 37e462ed3617..2860272abf05 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/BaseTableInputFormat.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/BaseTableInputFormat.java @@ -21,13 +21,14 @@ import org.apache.hadoop.hbase.filter.FilterList; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.storage.common.predicate.query.ElementQuery; -import org.gradoop.storage.impl.hbase.filter.HBaseFilterUtils; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import javax.annotation.Nonnull; /** * Base class for common functionality of HBase input formats + * * @param type of EPGM element */ abstract class BaseTableInputFormat extends TableInputFormat> { @@ -38,10 +39,7 @@ abstract class BaseTableInputFormat extends TableInputFor * @param query the query that represents a filter * @param scan the HBase scan instance on which the filter will be applied */ - void attachFilter( - @Nonnull ElementQuery> query, - @Nonnull Scan scan - ) { + void attachFilter(@Nonnull ElementQuery> query, @Nonnull Scan scan) { FilterList conjunctFilters = new FilterList(FilterList.Operator.MUST_PASS_ALL); if (query.getQueryRanges() != null && !query.getQueryRanges().isEmpty()) { @@ -49,7 +47,7 @@ void attachFilter( } if (query.getFilterPredicate() != null) { - conjunctFilters.addFilter(query.getFilterPredicate().toHBaseFilter()); + conjunctFilters.addFilter(query.getFilterPredicate().toHBaseFilter(false)); } // if there are filters inside the root list, add it to the Scan object diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/EdgeTableInputFormat.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/EdgeTableInputFormat.java index c39ca3d2d535..0bf46975606c 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/EdgeTableInputFormat.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/EdgeTableInputFormat.java @@ -22,8 +22,6 @@ import org.gradoop.storage.common.api.EPGMGraphOutput; import org.gradoop.storage.impl.hbase.api.EdgeHandler; -import java.io.IOException; - /** * Reads edge data from HBase. */ @@ -81,10 +79,6 @@ protected String getTableName() { */ @Override protected Tuple1 mapResultToTuple(Result result) { - try { - return new Tuple1<>(edgeHandler.readEdge(result)); - } catch (IOException e) { - throw new RuntimeException(e); - } + return new Tuple1<>(edgeHandler.readEdge(result)); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/GraphHeadTableInputFormat.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/GraphHeadTableInputFormat.java index 979544eb83fd..0340949b1386 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/GraphHeadTableInputFormat.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/GraphHeadTableInputFormat.java @@ -22,8 +22,6 @@ import org.gradoop.storage.common.api.EPGMGraphOutput; import org.gradoop.storage.impl.hbase.api.GraphHeadHandler; -import java.io.IOException; - /** * Reads graph data from HBase. */ @@ -82,10 +80,6 @@ protected String getTableName() { */ @Override protected Tuple1 mapResultToTuple(Result result) { - try { - return new Tuple1<>(graphHeadHandler.readGraphHead(result)); - } catch (IOException e) { - throw new RuntimeException(e); - } + return new Tuple1<>(graphHeadHandler.readGraphHead(result)); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/VertexTableInputFormat.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/VertexTableInputFormat.java index bb51d3b94fdb..d2abda2df0ad 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/VertexTableInputFormat.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/io/inputformats/VertexTableInputFormat.java @@ -22,8 +22,6 @@ import org.gradoop.storage.common.api.EPGMGraphOutput; import org.gradoop.storage.impl.hbase.api.VertexHandler; -import java.io.IOException; - /** * Reads vertex data from HBase. */ @@ -81,10 +79,6 @@ protected String getTableName() { */ @Override protected Tuple1 mapResultToTuple(Result result) { - try { - return new Tuple1<>(vertexHandler.readVertex(result)); - } catch (IOException e) { - throw new RuntimeException(e); - } + return new Tuple1<>(vertexHandler.readVertex(result)); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseEdgeIterator.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseEdgeIterator.java index 41f2a72118fe..793964d38601 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseEdgeIterator.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseEdgeIterator.java @@ -21,7 +21,6 @@ import org.gradoop.storage.common.iterator.ClosableIterator; import org.gradoop.storage.impl.hbase.api.EdgeHandler; -import java.io.IOException; import java.util.Iterator; /** @@ -78,10 +77,6 @@ public boolean hasNext() { @Override public Edge next() { - try { - return handler.readEdge(result); - } catch (IOException e) { - throw new RuntimeException(e); - } + return handler.readEdge(result); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseGraphIterator.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseGraphIterator.java index 0b2bd8350bf1..dfe62130671d 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseGraphIterator.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseGraphIterator.java @@ -21,7 +21,6 @@ import org.gradoop.storage.common.iterator.ClosableIterator; import org.gradoop.storage.impl.hbase.api.GraphHeadHandler; -import java.io.IOException; import java.util.Iterator; /** @@ -81,10 +80,6 @@ public boolean hasNext() { @Override public GraphHead next() { - try { - return handler.readGraphHead(result); - } catch (IOException e) { - throw new RuntimeException(e); - } + return handler.readGraphHead(result); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBasePropertyValueWrapper.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBasePropertyValueWrapper.java deleted file mode 100644 index 944f8fe96c20..000000000000 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBasePropertyValueWrapper.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.hbase.iterator; - -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.io.Writable; -import org.gradoop.common.model.impl.id.GradoopId; -import org.gradoop.common.model.impl.properties.DateTimeSerializer; -import org.gradoop.common.model.impl.properties.PropertyValue; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Wraps a property value to implement HBase's Writable interface. - */ -public class HBasePropertyValueWrapper implements Writable { - - /** - * Wrapped value. - */ - private final PropertyValue value; - - /** - * Constructor. - * - * @param value value to wrap - */ - public HBasePropertyValueWrapper(PropertyValue value) { - this.value = value; - } - - /** - * Byte representation: - * - * byte 1 : type info - * - * for dynamic length types (e.g. String and BigDecimal) - * byte 2 : length (short) - * byte 3 : length (short) - * byte 4 - end : value bytes - * - * for fixed length types (e.g. int, long, float, ...) - * byte 2 - end : value bytes - * - * @param dataOutput data output to write data to - * @throws IOException if writing to output fails - */ - @Override - public void write(DataOutput dataOutput) throws IOException { - byte[] rawBytes = value.getRawBytes(); - - // null? - // type - dataOutput.writeByte(rawBytes[0]); - // dynamic type? - if (rawBytes[0] == PropertyValue.TYPE_STRING || rawBytes[0] == PropertyValue.TYPE_BIG_DECIMAL || - rawBytes[0] == PropertyValue.TYPE_MAP || rawBytes[0] == PropertyValue.TYPE_LIST) { - // write length - dataOutput.writeShort(rawBytes.length - PropertyValue.OFFSET); - } - // write data - dataOutput.write(rawBytes, PropertyValue.OFFSET, rawBytes.length - PropertyValue.OFFSET); - } - - @Override - public void readFields(DataInput dataInput) throws IOException { - short length = 0; - // type - byte type = dataInput.readByte(); - // dynamic type? - if (type == PropertyValue.TYPE_STRING || type == PropertyValue.TYPE_BIG_DECIMAL || - type == PropertyValue.TYPE_MAP || type == PropertyValue.TYPE_LIST) { - // read length - length = dataInput.readShort(); - } else if (type == PropertyValue.TYPE_NULL) { - length = 0; - } else if (type == PropertyValue.TYPE_BOOLEAN) { - length = Bytes.SIZEOF_BOOLEAN; - } else if (type == PropertyValue.TYPE_INTEGER) { - length = Bytes.SIZEOF_INT; - } else if (type == PropertyValue.TYPE_LONG) { - length = Bytes.SIZEOF_LONG; - } else if (type == PropertyValue.TYPE_FLOAT) { - length = Bytes.SIZEOF_FLOAT; - } else if (type == PropertyValue.TYPE_DOUBLE) { - length = Bytes.SIZEOF_DOUBLE; - } else if (type == PropertyValue.TYPE_GRADOOP_ID) { - length = GradoopId.ID_SIZE; - } else if (type == PropertyValue.TYPE_DATE) { - length = DateTimeSerializer.SIZEOF_DATE; - } else if (type == PropertyValue.TYPE_TIME) { - length = DateTimeSerializer.SIZEOF_TIME; - } else if (type == PropertyValue.TYPE_DATETIME) { - length = DateTimeSerializer.SIZEOF_DATETIME; - } - // init new array - byte[] rawBytes = new byte[PropertyValue.OFFSET + length]; - // read type info - rawBytes[0] = type; - // read data - for (int i = PropertyValue.OFFSET; i < rawBytes.length; i++) { - rawBytes[i] = dataInput.readByte(); - } - - value.setBytes(rawBytes); - } -} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseVertexIterator.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseVertexIterator.java index 63d6e58abdd5..8687855b0fae 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseVertexIterator.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/iterator/HBaseVertexIterator.java @@ -21,7 +21,6 @@ import org.gradoop.storage.common.iterator.ClosableIterator; import org.gradoop.storage.impl.hbase.api.VertexHandler; -import java.io.IOException; import java.util.Iterator; /** @@ -81,11 +80,7 @@ public boolean hasNext() { @Override public Vertex next() { - try { - return handler.readVertex(result); - } catch (IOException e) { - throw new RuntimeException(e); - } + return handler.readVertex(result); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/HBaseFilterUtils.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/HBaseFilterUtils.java new file mode 100644 index 000000000000..e6f5ed5f832e --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/HBaseFilterUtils.java @@ -0,0 +1,256 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter; + +import org.apache.hadoop.hbase.filter.BinaryComparator; +import org.apache.hadoop.hbase.filter.CompareFilter; +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.RegexStringComparator; +import org.apache.hadoop.hbase.filter.RowFilter; +import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; +import org.apache.hadoop.hbase.util.Bytes; +import org.gradoop.common.model.impl.id.GradoopId; +import org.gradoop.common.model.impl.id.GradoopIdSet; +import org.gradoop.common.model.impl.properties.PropertyValue; +import org.gradoop.common.model.impl.properties.PropertyValueUtils; + +import javax.annotation.Nonnull; +import java.util.Set; +import java.util.regex.Pattern; + +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_META; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_VALUE; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_TYPE; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.COL_LABEL; + +/** + * Utility class for common HBase filter tasks + */ +public class HBaseFilterUtils { + /** + * Byte representation of meta data column family + */ + private static final byte[] CF_META_BYTES = Bytes.toBytesBinary(CF_META); + /** + * Byte representation of property value column family + */ + private static final byte[] CF_PROPERTY_VALUE_BYTES = Bytes.toBytesBinary(CF_PROPERTY_VALUE); + /** + * Byte representation of property type column family + */ + private static final byte[] CF_PROPERTY_TYPE_BYTES = Bytes.toBytesBinary(CF_PROPERTY_TYPE); + /** + * Byte representation of column qualifier + */ + private static final byte[] COL_LABEL_BYTES = Bytes.toBytesBinary(COL_LABEL); + + /** + * Creates a HBase Filter object to return only graph elements that are equal to the given + * GradoopIds. + * + * @param elementIds a set of graph element GradoopIds to filter + * @return a HBase Filter object + */ + public static Filter getIdFilter(GradoopIdSet elementIds) { + FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); + + for (GradoopId gradoopId : elementIds) { + RowFilter rowFilter = new RowFilter( + CompareFilter.CompareOp.EQUAL, + new BinaryComparator(gradoopId.toByteArray()) + ); + filterList.addFilter(rowFilter); + } + return filterList; + } + + /** + * Creates a HBase Filter object representation of labelIn predicate + * + * @param labels set of labels to filter for + * @param negate flag to define if this filter should be negated + * @return the HBase filter representation + */ + public static Filter getLabelInFilter(@Nonnull Set labels, boolean negate) { + // Handle negation + CompareFilter.CompareOp compareOp = negate ? CompareFilter.CompareOp.NOT_EQUAL : + CompareFilter.CompareOp.EQUAL; + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ALL : + FilterList.Operator.MUST_PASS_ONE; + + FilterList filterList = new FilterList(listOperator); + + labels.stream() + .map(label -> new SingleColumnValueFilter(CF_META_BYTES, COL_LABEL_BYTES, compareOp, + Bytes.toBytesBinary(label))) + .forEach(filterList::addFilter); + + return filterList; + } + + /** + * Creates a HBase Filter object representation of labelReg predicate + * + * @param reg the pattern to filter for + * @param negate flag to define if this filter should be negated + * @return the HBase filter representation + */ + public static Filter getLabelRegFilter(@Nonnull Pattern reg, boolean negate) { + return new SingleColumnValueFilter( + CF_META_BYTES, + COL_LABEL_BYTES, + negate ? CompareFilter.CompareOp.NOT_EQUAL : CompareFilter.CompareOp.EQUAL, + new RegexStringComparator(reg.pattern()) + ); + } + + /** + * Creates a HBase Filter object representation of propEquals predicate + * + * @param key the property key to filter for + * @param value the value to filter for + * @param negate flag to define if this filter should be negated + * @return the HBase filter representation + */ + public static Filter getPropEqualsFilter(@Nonnull String key, @Nonnull PropertyValue value, + boolean negate) { + // Handle negation + CompareFilter.CompareOp compareOp = negate ? CompareFilter.CompareOp.NOT_EQUAL : + CompareFilter.CompareOp.EQUAL; + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ONE : + FilterList.Operator.MUST_PASS_ALL; + + FilterList filterList = new FilterList(listOperator); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + CF_PROPERTY_VALUE_BYTES, + Bytes.toBytesBinary(key), + compareOp, + PropertyValueUtils.Bytes.getRawBytesWithoutType(value)); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + CF_PROPERTY_TYPE_BYTES, + Bytes.toBytesBinary(key), + compareOp, + PropertyValueUtils.Bytes.getTypeByte(value)); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + filterList.addFilter(valueFilter); + filterList.addFilter(typeFilter); + return filterList; + } + + /** + * Creates a HBase Filter object representation of propReg predicate + * + * @param key the property key to filter for + * @param reg the pattern to search for + * @param negate flag to define if this filter should be negated + * @return the HBase filter representation + */ + public static Filter getPropRegFilter(@Nonnull String key, @Nonnull Pattern reg, boolean negate) { + // Handle negation + CompareFilter.CompareOp compareOp = negate ? CompareFilter.CompareOp.NOT_EQUAL : + CompareFilter.CompareOp.EQUAL; + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ONE : + FilterList.Operator.MUST_PASS_ALL; + + FilterList filterList = new FilterList(listOperator); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + CF_PROPERTY_VALUE_BYTES, + Bytes.toBytesBinary(key), + compareOp, + new RegexStringComparator(reg.pattern())); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + CF_PROPERTY_TYPE_BYTES, + Bytes.toBytesBinary(key), + compareOp, + new byte[] {PropertyValue.TYPE_STRING}); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + filterList.addFilter(typeFilter); + filterList.addFilter(valueFilter); + return filterList; + } + + /** + * Creates a HBase Filter object representation of propLargerThan predicate + * + * @param key the property key to filter for + * @param min the property value that defines the minimum of the filter + * @param include a flag to define if a value that is equal to min should be included + * @param negate flag to define if this filter should be negated + * @return the HBase filter representation + */ + public static Filter getPropLargerThanFilter(@Nonnull String key, @Nonnull PropertyValue min, + boolean include, boolean negate) { + // Handle negation + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ONE : + FilterList.Operator.MUST_PASS_ALL; + + CompareFilter.CompareOp compareOp; + if (include) { + if (negate) { + compareOp = CompareFilter.CompareOp.LESS; + } else { + compareOp = CompareFilter.CompareOp.GREATER_OR_EQUAL; + } + } else { + if (negate) { + compareOp = CompareFilter.CompareOp.LESS_OR_EQUAL; + } else { + compareOp = CompareFilter.CompareOp.GREATER; + } + } + + FilterList filterList = new FilterList(listOperator); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + CF_PROPERTY_VALUE_BYTES, + Bytes.toBytesBinary(key), + compareOp, + new BinaryComparator(PropertyValueUtils.Bytes.getRawBytesWithoutType(min))); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + CF_PROPERTY_TYPE_BYTES, + Bytes.toBytesBinary(key), + negate ? CompareFilter.CompareOp.NOT_EQUAL : CompareFilter.CompareOp.EQUAL, + PropertyValueUtils.Bytes.getTypeByte(min)); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + filterList.addFilter(valueFilter); + filterList.addFilter(typeFilter); + return filterList; + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilter.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/HBaseElementFilter.java similarity index 74% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilter.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/HBaseElementFilter.java index 0ce8adf227cc..f3fb579fd402 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilter.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/HBaseElementFilter.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.gradoop.storage.impl.hbase.filter.api; +package org.gradoop.storage.impl.hbase.predicate.filter.api; -import org.apache.commons.lang.NotImplementedException; import org.apache.hadoop.hbase.filter.Filter; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.storage.common.predicate.filter.api.ElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.calculate.And; +import org.gradoop.storage.impl.hbase.predicate.filter.calculate.Not; +import org.gradoop.storage.impl.hbase.predicate.filter.calculate.Or; import javax.annotation.Nonnull; import java.io.Serializable; @@ -31,33 +33,40 @@ public interface HBaseElementFilter extends ElementFilter>, Serializable { + /** + * {@inheritDoc} + */ @Nonnull @Override default HBaseElementFilter or(@Nonnull HBaseElementFilter another) { - // this will be implemented at issue #857 - throw new NotImplementedException("Logical 'or' not implemented."); + return Or.create(this, another); } + /** + * {@inheritDoc} + */ @Nonnull @Override default HBaseElementFilter and(@Nonnull HBaseElementFilter another) { - // this will be implemented at issue #857 - throw new NotImplementedException("Logical 'and' not implemented."); + return And.create(this, another); } + /** + * {@inheritDoc} + */ @Nonnull @Override default HBaseElementFilter negate() { - // this will be implemented at issue #857 - throw new NotImplementedException("Logical negation not implemented."); + return Not.of(this); } /** * Translate the filter to a HBase specific {@link Filter} which can be applied * to a {@link org.apache.hadoop.hbase.client.Scan} instance. * + * @param negate flag to negate the filter * @return the translated filter instance */ @Nonnull - Filter toHBaseFilter(); + Filter toHBaseFilter(boolean negate); } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/package-info.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/package-info.java similarity index 92% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/package-info.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/package-info.java index 39db535abec6..7bf1bfa26ea4 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/api/package-info.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/api/package-info.java @@ -16,4 +16,4 @@ /** * Contains filter API interface related to HBase predicate definitions. */ -package org.gradoop.storage.impl.hbase.filter.api; +package org.gradoop.storage.impl.hbase.predicate.filter.api; diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/And.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/And.java new file mode 100644 index 000000000000..1fde4dc7968a --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/And.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.calculate; + +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringJoiner; + +/** + * Conjunctive predicate filter + * + * @param element type + */ +public final class And implements HBaseElementFilter { + + /** + * Predicate list + */ + private final List> predicates = new ArrayList<>(); + + /** + * Creates a new conjunctive filter chain + * + * @param predicates the predicates to combine with a logical and + */ + private And(List> predicates) { + if (predicates.size() < 2) { + throw new IllegalArgumentException(String.format("predicates len(=%d) < 2", + predicates.size())); + } + this.predicates.addAll(predicates); + } + + /** + * Create a conjunctive formula + * + * @param predicates filter predicate + * @param input type + * @return Conjunctive filter instance + */ + @SafeVarargs + public static And create(HBaseElementFilter... predicates) { + List> formula = new ArrayList<>(); + Collections.addAll(formula, predicates); + return new And<>(formula); + } + + /** + * {@inheritDoc} + */ + @Nonnull + @Override + public Filter toHBaseFilter(boolean negate) { + // If filter is negated, logical AND will be transformed to logical OR + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ONE : + FilterList.Operator.MUST_PASS_ALL; + FilterList filterList = new FilterList(listOperator); + // Add each filter to filter list + predicates.stream() + .map(predicate -> predicate.toHBaseFilter(negate)) + .forEach(filterList::addFilter); + + return filterList; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringJoiner joiner = new StringJoiner(" AND "); + for (HBaseElementFilter predicate : predicates) { + joiner.add("(" + predicate.toString() + ")"); + } + return joiner.toString(); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Not.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Not.java new file mode 100644 index 000000000000..8d12258021fb --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Not.java @@ -0,0 +1,73 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.calculate; + +import org.apache.hadoop.hbase.filter.Filter; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; + +/** + * Negated filter + * + * @param input type + */ +public final class Not implements HBaseElementFilter { + + /** + * The predicate to negate + */ + private final HBaseElementFilter predicate; + + /** + * Create a new negated predicate + * + * @param predicate predicate + */ + private Not(HBaseElementFilter predicate) { + this.predicate = predicate; + } + + /** + * Create a negative formula + * + * @param predicate predicate to negate + * @param input type + * @return negated filter instance + */ + public static Not of(HBaseElementFilter predicate) { + return new Not<>(predicate); + } + + /** + * {@inheritDoc} + */ + @Nonnull + @Override + public Filter toHBaseFilter(boolean negate) { + // Toggle negation to prevent double negation while fetching filter instance + return predicate.toHBaseFilter(!negate); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "NOT " + predicate; + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Or.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Or.java new file mode 100644 index 000000000000..0d18e6da01a6 --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/Or.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.calculate; + +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringJoiner; + +/** + * Disjunctive predicate filter + * + * @param element type + */ +public final class Or implements HBaseElementFilter { + + /** + * Predicate list + */ + private final List> predicates = new ArrayList<>(); + + /** + * Creates a new disjunctive filter chain + * + * @param predicates the predicates to combine with a logical or + */ + private Or(List> predicates) { + if (predicates.size() < 2) { + throw new IllegalArgumentException(String.format("predicates len(=%d) < 2", + predicates.size())); + } + this.predicates.addAll(predicates); + } + + /** + * Create a disjunctive formula + * + * @param predicates filter predicate + * @param input type + * @return Disjunctive filter instance + */ + @SafeVarargs + public static Or create(HBaseElementFilter... predicates) { + List> formula = new ArrayList<>(); + Collections.addAll(formula, predicates); + return new Or<>(formula); + } + + /** + * {@inheritDoc} + */ + @Nonnull + @Override + public Filter toHBaseFilter(boolean negate) { + // If filter is negated, logical OR will be transformed to logical AND + FilterList.Operator listOperator = negate ? FilterList.Operator.MUST_PASS_ALL : + FilterList.Operator.MUST_PASS_ONE; + FilterList filterList = new FilterList(listOperator); + // Add each filter to filter list + predicates.stream() + .map(predicate -> predicate.toHBaseFilter(negate)) + .forEach(filterList::addFilter); + + return filterList; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringJoiner joiner = new StringJoiner(" OR "); + for (HBaseElementFilter predicate : predicates) { + joiner.add("(" + predicate.toString() + ")"); + } + return joiner.toString(); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/package-info.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/package-info.java new file mode 100644 index 000000000000..a4f7857ec6c3 --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/calculate/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * Contains logical expressions for HBase predicates + */ +package org.gradoop.storage.impl.hbase.predicate.filter.calculate; diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelIn.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelIn.java similarity index 56% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelIn.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelIn.java index 0f787568bc55..d929222d3ff0 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelIn.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelIn.java @@ -13,22 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.gradoop.storage.impl.hbase.filter.impl; +package org.gradoop.storage.impl.hbase.predicate.filter.impl; -import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.filter.Filter; -import org.apache.hadoop.hbase.filter.FilterList; -import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; -import org.apache.hadoop.hbase.util.Bytes; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.storage.common.predicate.filter.impl.LabelIn; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import javax.annotation.Nonnull; -import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_META; -import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.COL_LABEL; - /** * HBase label equality predicate implementation * @@ -46,20 +40,12 @@ public HBaseLabelIn(String... labels) { super(labels); } + /** + * {@inheritDoc} + */ @Nonnull @Override - public Filter toHBaseFilter() { - FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); - - for (String label : getLabels()) { - SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( - Bytes.toBytesBinary(CF_META), - Bytes.toBytesBinary(COL_LABEL), - CompareFilter.CompareOp.EQUAL, - Bytes.toBytesBinary(label) - ); - filterList.addFilter(valueFilter); - } - return filterList; + public Filter toHBaseFilter(boolean negate) { + return HBaseFilterUtils.getLabelInFilter(getLabels(), negate); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelReg.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelReg.java similarity index 63% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelReg.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelReg.java index bf88a1e3ebd0..d95419304da7 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelReg.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelReg.java @@ -13,23 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.gradoop.storage.impl.hbase.filter.impl; +package org.gradoop.storage.impl.hbase.predicate.filter.impl; -import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.filter.Filter; -import org.apache.hadoop.hbase.filter.RegexStringComparator; -import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; -import org.apache.hadoop.hbase.util.Bytes; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.storage.common.predicate.filter.impl.LabelReg; -import org.gradoop.storage.impl.hbase.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; import javax.annotation.Nonnull; import java.util.regex.Pattern; -import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_META; -import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.COL_LABEL; - /** * HBase label regex predicate implementation * @@ -47,14 +41,12 @@ public HBaseLabelReg(Pattern reg) { super(reg); } + /** + * {@inheritDoc} + */ @Nonnull @Override - public Filter toHBaseFilter() { - return new SingleColumnValueFilter( - Bytes.toBytesBinary(CF_META), - Bytes.toBytesBinary(COL_LABEL), - CompareFilter.CompareOp.EQUAL, - new RegexStringComparator(getReg().pattern()) - ); + public Filter toHBaseFilter(boolean negate) { + return HBaseFilterUtils.getLabelRegFilter(getReg(), negate); } } diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEquals.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEquals.java new file mode 100644 index 000000000000..a2cde9e053b2 --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEquals.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.Filter; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.common.predicate.filter.impl.PropEquals; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; + +/** + * HBase property equality implementation + * + * @param EPGM element type + */ +public class HBasePropEquals extends PropEquals> + implements HBaseElementFilter { + + /** + * Property equals filter + * + * @param key property key + * @param value property value + */ + public HBasePropEquals(@Nonnull String key, @Nonnull Object value) { + super(key, value); + } + + /** + * {@inheritDoc} + */ + @Override + @Nonnull + public Filter toHBaseFilter(boolean negate) { + return HBaseFilterUtils.getPropEqualsFilter(getKey(), getValue(), negate); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThan.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThan.java new file mode 100644 index 000000000000..4f05042049c7 --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThan.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.Filter; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.common.predicate.filter.impl.PropLargerThan; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; + +/** + * HBase property value compare predicate implement + * + * @param EPGM element type + */ +public class HBasePropLargerThan + extends PropLargerThan> implements HBaseElementFilter { + + /** + * Create a new property compare filter + * + * @param key property key + * @param min property min value + * @param include include min value + */ + public HBasePropLargerThan(@Nonnull String key, @Nonnull Object min, boolean include) { + super(key, min, include); + } + + /** + * {@inheritDoc} + */ + @Nonnull + @Override + public Filter toHBaseFilter(boolean negate) { + return HBaseFilterUtils.getPropLargerThanFilter(getKey(), getMin(), isInclude(), negate); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropReg.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropReg.java new file mode 100644 index 000000000000..df80364413ee --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropReg.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.Filter; +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.common.predicate.filter.impl.PropReg; +import org.gradoop.storage.impl.hbase.predicate.filter.HBaseFilterUtils; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; + +import javax.annotation.Nonnull; +import java.util.regex.Pattern; + +/** + * HBase property regex filter implementation + * + * @param EPGM element type + */ +public class HBasePropReg extends PropReg> + implements HBaseElementFilter { + + /** + * Property regex filter constructor + * + * @param key property key + * @param reg label regex + */ + public HBasePropReg(@Nonnull String key, @Nonnull Pattern reg) { + super(key, reg); + } + + /** + * {@inheritDoc} + */ + @Nonnull + @Override + public Filter toHBaseFilter(boolean negate) { + return HBaseFilterUtils.getPropRegFilter(getKey(), getReg(), negate); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/package-info.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/package-info.java similarity index 91% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/package-info.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/package-info.java index 03884695a44e..d52938809b43 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/impl/package-info.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/package-info.java @@ -16,4 +16,4 @@ /** * Specific filter implementations of HBase store */ -package org.gradoop.storage.impl.hbase.filter.impl; +package org.gradoop.storage.impl.hbase.predicate.filter.impl; diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/package-info.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/package-info.java similarity index 92% rename from gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/package-info.java rename to gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/package-info.java index 8679dfda5779..e7620f63b0aa 100644 --- a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/filter/package-info.java +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/impl/hbase/predicate/filter/package-info.java @@ -16,4 +16,4 @@ /** * Contains utility classes for common HBase filter tasks */ -package org.gradoop.storage.impl.hbase.filter; +package org.gradoop.storage.impl.hbase.predicate.filter; diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/HBaseFilters.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/HBaseFilters.java new file mode 100644 index 000000000000..3def39d1356c --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/HBaseFilters.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.utils; + +import org.gradoop.common.model.api.entities.EPGMElement; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelIn; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelReg; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropEquals; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropLargerThan; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropReg; + +import javax.annotation.Nonnull; +import java.util.regex.Pattern; + +/** + * HBase filter collection utilities + */ +public class HBaseFilters { + + /** + * Static generator function for labelIn predicate to apply on a HBase store. + * See {@link HBaseLabelIn} for further details. + * + * @param value value ranges + * @param epgm element type + * @return HBaseLabelIn filter instance + */ + @Nonnull + public static HBaseLabelIn labelIn(@Nonnull String... value) { + return new HBaseLabelIn<>(value); + } + + /** + * Static generator function for labelReg predicate to apply on a HBase store. + * See {@link HBaseLabelReg} for further details. + * + * @param reg regex pattern + * @param epgm element type + * @return HBaseLabelReg filter instance + */ + @Nonnull + public static HBaseLabelReg labelReg(@Nonnull Pattern reg) { + return new HBaseLabelReg<>(reg); + } + + /** + * Static generator function for propEquals predicate to apply on a HBase store. + * See {@link HBasePropEquals} for further details. + * + * @param key property key + * @param value property value + * @param epgm element type + * @return HBasePropEquals filter instance + */ + @Nonnull + public static HBasePropEquals propEquals( + @Nonnull String key, + @Nonnull Object value + ) { + return new HBasePropEquals<>(key, value); + } + + /** + * Static generator function for propLargerThan predicate to apply on a HBase store. + * See {@link HBasePropLargerThan} for further details. + * + * @param key property key + * @param value property value + * @param include should include value + * @param epgm element type + * @return HBasePropLargerThan filter instance + */ + @Nonnull + public static HBasePropLargerThan propLargerThan( + @Nonnull String key, + Object value, + boolean include) { + return new HBasePropLargerThan<>(key, value, include); + } + + /** + * Static generator function for propReg predicate to apply on a HBase store. + * See {@link HBasePropReg} for further details. + * + * @param key property key + * @param pattern property pattern + * @param epgm element type + * @return HBasePropReg filter instance + */ + @Nonnull + public static HBasePropReg propReg( + @Nonnull String key, + @Nonnull Pattern pattern) { + return new HBasePropReg<>(key, pattern); + } +} diff --git a/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/package-info.java b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/package-info.java new file mode 100644 index 000000000000..1a56e50c87c1 --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/main/java/org/gradoop/storage/utils/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +/** + * HBase filter utilities + */ +package org.gradoop.storage.utils; diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/GradoopHBaseTestBase.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/GradoopHBaseTestBase.java index 9acf06e5b199..27c579f0f9f5 100644 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/GradoopHBaseTestBase.java +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/GradoopHBaseTestBase.java @@ -15,7 +15,6 @@ */ package org.gradoop.storage.impl.hbase; -import org.apache.flink.api.java.ExecutionEnvironment; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseTestingUtility; @@ -24,7 +23,6 @@ import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.storage.config.GradoopHBaseConfig; -import org.gradoop.storage.impl.hbase.HBaseEPGMStore; import org.gradoop.storage.impl.hbase.factory.HBaseEPGMStoreFactory; import java.io.IOException; @@ -44,6 +42,17 @@ public class GradoopHBaseTestBase { public static final Pattern PATTERN_GRAPH = Pattern.compile("^Com.*"); public static final Pattern PATTERN_VERTEX = Pattern.compile("^(Per|Ta).*"); public static final Pattern PATTERN_EDGE = Pattern.compile("^has.*"); + public static final Pattern PATTERN_GRAPH_PROP = Pattern.compile(".*doop$"); + public static final Pattern PATTERN_VERTEX_PROP = Pattern.compile(".*ve$"); + public static final Pattern PATTERN_EDGE_PROP = Pattern.compile("^start..$"); + + public static final String PROP_AGE = "age"; + public static final String PROP_CITY = "city"; + public static final String PROP_INTEREST = "interest"; + public static final String PROP_NAME = "name"; + public static final String PROP_SINCE = "since"; + public static final String PROP_STATUS = "status"; + public static final String PROP_VERTEX_COUNT = "vertexCount"; private static Collection socialGraphHeads; private static Collection socialVertices; @@ -89,31 +98,29 @@ public static void tearDownHBase() throws Exception { /** * Initializes and returns an empty graph store. * - * @param env the execution environment * @return empty HBase graph store */ - public static HBaseEPGMStore createEmptyEPGMStore(ExecutionEnvironment env) { + public static HBaseEPGMStore createEmptyEPGMStore() { Configuration config = utility.getConfiguration(); HBaseEPGMStoreFactory.deleteEPGMStore(config); return HBaseEPGMStoreFactory.createOrOpenEPGMStore(config, - GradoopHBaseConfig.getDefaultConfig(env)); + GradoopHBaseConfig.getDefaultConfig()); } /** * Initializes and returns an empty graph store with a prefix at each table name. * - * @param env the execution environment * @param prefix the table prefix * @return empty HBase graph store */ - public static HBaseEPGMStore createEmptyEPGMStore(ExecutionEnvironment env, String prefix) { + public static HBaseEPGMStore createEmptyEPGMStore(String prefix) { Configuration config = utility.getConfiguration(); HBaseEPGMStoreFactory.deleteEPGMStore(config, prefix); return HBaseEPGMStoreFactory.createOrOpenEPGMStore( config, - GradoopHBaseConfig.getDefaultConfig(env), + GradoopHBaseConfig.getDefaultConfig(), prefix ); } @@ -122,13 +129,12 @@ public static HBaseEPGMStore createEmptyEPGMStore(ExecutionEnvironment env, Stri * Open existing EPGMStore for test purposes. If the store does not exist, a * new one will be initialized and returned. * - * @param env the execution environment * @return EPGMStore with vertices and edges */ - public static HBaseEPGMStore openEPGMStore(ExecutionEnvironment env) { + public static HBaseEPGMStore openEPGMStore() { return HBaseEPGMStoreFactory.createOrOpenEPGMStore( utility.getConfiguration(), - GradoopHBaseConfig.getDefaultConfig(env) + GradoopHBaseConfig.getDefaultConfig() ); } @@ -136,20 +142,18 @@ public static HBaseEPGMStore openEPGMStore(ExecutionEnvironment env) { * Open existing EPGMStore for test purposes. If the store does not exist, a * new one will be initialized and returned. * - * @param env the execution environment * @param prefix the table prefix * @return EPGMStore with vertices and edges */ - public static HBaseEPGMStore openEPGMStore(ExecutionEnvironment env, String prefix) { + public static HBaseEPGMStore openEPGMStore(String prefix) { return HBaseEPGMStoreFactory.createOrOpenEPGMStore( utility.getConfiguration(), - GradoopHBaseConfig.getDefaultConfig(env), + GradoopHBaseConfig.getDefaultConfig(), prefix ); } - //---------------------------------------------------------------------------- // Data generation //---------------------------------------------------------------------------- diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/HBaseGraphStoreTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/HBaseGraphStoreTest.java index 338b59f59fd4..1864af84bb5e 100644 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/HBaseGraphStoreTest.java +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/HBaseGraphStoreTest.java @@ -16,7 +16,7 @@ package org.gradoop.storage.impl.hbase; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import com.google.common.collect.Queues; import org.gradoop.common.config.GradoopConfig; import org.gradoop.common.exceptions.UnsupportedTypeException; import org.gradoop.common.model.api.entities.EPGMEdge; @@ -31,10 +31,16 @@ import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.common.model.impl.pojo.VertexFactory; import org.gradoop.common.model.impl.properties.Properties; +import org.gradoop.common.model.impl.properties.PropertyValue; import org.gradoop.common.util.AsciiGraphLoader; import org.gradoop.storage.common.predicate.query.Query; -import org.gradoop.storage.impl.hbase.filter.impl.HBaseLabelIn; -import org.gradoop.storage.impl.hbase.filter.impl.HBaseLabelReg; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelIn; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelReg; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropEquals; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropLargerThan; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropReg; +import org.gradoop.storage.utils.HBaseFilters; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.FixMethodOrder; @@ -43,11 +49,46 @@ import java.io.IOException; import java.util.List; -import java.util.Set; +import java.util.Queue; import java.util.stream.Collectors; -import static org.apache.flink.api.java.ExecutionEnvironment.getExecutionEnvironment; -import static org.gradoop.common.GradoopTestUtils.*; +import static org.gradoop.common.GradoopTestUtils.BIG_DECIMAL_VAL_7; +import static org.gradoop.common.GradoopTestUtils.BOOL_VAL_1; +import static org.gradoop.common.GradoopTestUtils.DATETIME_VAL_d; +import static org.gradoop.common.GradoopTestUtils.DATE_VAL_b; +import static org.gradoop.common.GradoopTestUtils.DOUBLE_VAL_5; +import static org.gradoop.common.GradoopTestUtils.FLOAT_VAL_4; +import static org.gradoop.common.GradoopTestUtils.GRADOOP_ID_VAL_8; +import static org.gradoop.common.GradoopTestUtils.INT_VAL_2; +import static org.gradoop.common.GradoopTestUtils.KEY_0; +import static org.gradoop.common.GradoopTestUtils.KEY_1; +import static org.gradoop.common.GradoopTestUtils.KEY_2; +import static org.gradoop.common.GradoopTestUtils.KEY_3; +import static org.gradoop.common.GradoopTestUtils.KEY_4; +import static org.gradoop.common.GradoopTestUtils.KEY_5; +import static org.gradoop.common.GradoopTestUtils.KEY_6; +import static org.gradoop.common.GradoopTestUtils.KEY_7; +import static org.gradoop.common.GradoopTestUtils.KEY_8; +import static org.gradoop.common.GradoopTestUtils.KEY_9; +import static org.gradoop.common.GradoopTestUtils.KEY_a; +import static org.gradoop.common.GradoopTestUtils.KEY_b; +import static org.gradoop.common.GradoopTestUtils.KEY_c; +import static org.gradoop.common.GradoopTestUtils.KEY_d; +import static org.gradoop.common.GradoopTestUtils.KEY_e; +import static org.gradoop.common.GradoopTestUtils.KEY_f; +import static org.gradoop.common.GradoopTestUtils.LIST_VAL_a; +import static org.gradoop.common.GradoopTestUtils.LONG_VAL_3; +import static org.gradoop.common.GradoopTestUtils.MAP_VAL_9; +import static org.gradoop.common.GradoopTestUtils.NULL_VAL_0; +import static org.gradoop.common.GradoopTestUtils.SET_VAL_f; +import static org.gradoop.common.GradoopTestUtils.SHORT_VAL_e; +import static org.gradoop.common.GradoopTestUtils.STRING_VAL_6; +import static org.gradoop.common.GradoopTestUtils.SUPPORTED_PROPERTIES; +import static org.gradoop.common.GradoopTestUtils.TIME_VAL_c; +import static org.gradoop.common.GradoopTestUtils.validateEPGMElementCollections; +import static org.gradoop.common.GradoopTestUtils.validateEPGMElements; +import static org.gradoop.common.GradoopTestUtils.validateEPGMGraphElementCollections; +import static org.gradoop.common.GradoopTestUtils.validateEPGMGraphElements; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -67,7 +108,7 @@ public class HBaseGraphStoreTest extends GradoopHBaseTestBase { */ @BeforeClass public static void setUp() throws IOException { - socialNetworkStore = openEPGMStore(getExecutionEnvironment(), "HBaseGraphStoreTest."); + socialNetworkStore = openEPGMStore("HBaseGraphStoreTest."); writeSocialGraphToStore(socialNetworkStore); } @@ -87,7 +128,7 @@ public static void tearDown() throws IOException { */ @Test public void writeCloseOpenReadTest() throws IOException { - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment()); + HBaseEPGMStore graphStore = createEmptyEPGMStore(); AsciiGraphLoader loader = getMinimalFullFeaturedGraphLoader(); @@ -101,7 +142,7 @@ public void writeCloseOpenReadTest() throws IOException { // re-open graphStore.close(); - graphStore = openEPGMStore(getExecutionEnvironment()); + graphStore = openEPGMStore(); // validate validateGraphHead(graphStore, graphHead); @@ -117,7 +158,7 @@ public void writeCloseOpenReadTest() throws IOException { @Test public void writeCloseOpenReadTestWithPrefix() throws IOException { String prefix = "test."; - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment(), prefix); + HBaseEPGMStore graphStore = createEmptyEPGMStore(prefix); AsciiGraphLoader loader = getMinimalFullFeaturedGraphLoader(); @@ -131,7 +172,7 @@ public void writeCloseOpenReadTestWithPrefix() throws IOException { // re-open graphStore.close(); - graphStore = openEPGMStore(getExecutionEnvironment(), prefix); + graphStore = openEPGMStore(prefix); // validate validateGraphHead(graphStore, graphHead); @@ -146,7 +187,7 @@ public void writeCloseOpenReadTestWithPrefix() throws IOException { */ @Test public void writeFlushReadTest() throws IOException { - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment()); + HBaseEPGMStore graphStore = createEmptyEPGMStore(); graphStore.setAutoFlush(false); AsciiGraphLoader loader = getMinimalFullFeaturedGraphLoader(); @@ -178,7 +219,7 @@ public void writeFlushReadTest() throws IOException { */ @Test public void iteratorTest() throws IOException { - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment()); + HBaseEPGMStore graphStore = createEmptyEPGMStore(); List vertices = Lists.newArrayList(getSocialVertices()); List edges = Lists.newArrayList(getSocialEdges()); @@ -225,16 +266,16 @@ public void iteratorTest() throws IOException { } /** - * Tries to add an unsupported property type {@link Set} as property value. + * Tries to add an unsupported property type {@link Queue} as property value. */ @Test(expected = UnsupportedTypeException.class) public void wrongPropertyTypeTest() throws IOException { - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment()); + HBaseEPGMStore graphStore = createEmptyEPGMStore(); EPGMVertexFactory vertexFactory = new VertexFactory(); - // Set is not supported by - final Set value = Sets.newHashSet(); + // Queue is not supported by + final Queue value = Queues.newPriorityQueue(); GradoopId vertexID = GradoopId.get(); final String label = "A"; @@ -254,7 +295,7 @@ public void wrongPropertyTypeTest() throws IOException { @SuppressWarnings("Duplicates") @Test public void propertyTypeTest() throws IOException { - HBaseEPGMStore graphStore = createEmptyEPGMStore(getExecutionEnvironment()); + HBaseEPGMStore graphStore = createEmptyEPGMStore(); EPGMVertexFactory vertexFactory = new VertexFactory(); @@ -333,6 +374,14 @@ public void propertyTypeTest() throws IOException { assertTrue(v.getPropertyValue(propertyKey).isDateTime()); assertEquals(DATETIME_VAL_d, v.getPropertyValue(propertyKey).getDateTime()); break; + case KEY_e: + assertTrue(v.getPropertyValue(propertyKey).isShort()); + assertEquals(SHORT_VAL_e, v.getPropertyValue(propertyKey).getShort()); + break; + case KEY_f: + assertTrue(v.getPropertyValue(propertyKey).isSet()); + assertEquals(SET_VAL_f, v.getPropertyValue(propertyKey).getSet()); + break; } } @@ -379,6 +428,87 @@ public void testGetGraphSpaceWithoutIdPredicate() throws IOException { validateEPGMElementCollections(graphHeads, queryResult); } + /** + * Test the getVertexSpace() method with an id filter predicate + */ + @Test + public void testGetVertexSpaceWithIdPredicate() throws IOException { + // Fetch all vertices from gdl file + List vertices = Lists.newArrayList(getSocialVertices()); + // Select only a subset + vertices = vertices.subList(1, 5); + + // Extract the vertex ids + GradoopIdSet ids = GradoopIdSet.fromExisting(vertices.stream() + .map(EPGMIdentifiable::getId) + .collect(Collectors.toList())); + // Query with the extracted ids + List queryResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromSets(ids) + .noFilter()) + .readRemainsAndClose(); + + validateEPGMElementCollections(vertices, queryResult); + } + + /** + * Test the getVertexSpace() method without an id filter predicate + */ + @Test + public void testGetVertexSpaceWithoutIdPredicate() throws IOException { + // Fetch all vertices from gdl file + List vertices = Lists.newArrayList(getSocialVertices()); + // Query the graph store with an empty predicate + List queryResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromAll() + .noFilter()) + .readRemainsAndClose(); + + validateEPGMElementCollections(vertices, queryResult); + } + + /** + * Test the getEdgeSpace() method with an id filter predicate + */ + @Test + public void testGetEdgeSpaceWithIdPredicate() throws IOException { + // Fetch all edges from gdl file + List edges = Lists.newArrayList(getSocialEdges()); + // Select only a subset + edges = edges.subList(3, 8); + // Extract the edge ids + GradoopIdSet ids = GradoopIdSet.fromExisting(edges.stream() + .map(EPGMIdentifiable::getId) + .collect(Collectors.toList())); + // Query with the extracted ids + List queryResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromSets(ids) + .noFilter()) + .readRemainsAndClose(); + + validateEPGMElementCollections(edges, queryResult); + } + + /** + * Test the getEdgeSpace() method without an id filter predicate + */ + @Test + public void testGetEdgeSpaceWithoutIdPredicate() throws IOException { + // Fetch all edges from gdl file + List edges = Lists.newArrayList(getSocialEdges()); + // Query the graph store with an empty predicate + List queryResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromAll() + .noFilter()) + .readRemainsAndClose(); + + validateEPGMElementCollections(edges, queryResult); + } + /** * Test the getGraphSpace(), getVertexSpace() and getEdgeSpace() method * with the {@link HBaseLabelIn} predicate @@ -399,26 +529,26 @@ public void testGetElementSpaceWithLabelInPredicate() throws IOException { List vertices = Lists.newArrayList(getSocialVertices()) .stream() - .filter(e -> (e.getLabel().equals(LABEL_TAG) || e.getLabel().equals(LABEL_FORUM))) + .filter(e -> (!e.getLabel().equals(LABEL_TAG) && !e.getLabel().equals(LABEL_FORUM))) .collect(Collectors.toList()); // Query the store List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() .fromAll() - .where(new HBaseLabelIn<>(LABEL_FORUM))) + .where(HBaseFilters.labelIn(LABEL_FORUM))) .readRemainsAndClose(); List edgeResult = socialNetworkStore.getEdgeSpace( Query.elements() .fromAll() - .where(new HBaseLabelIn<>(LABEL_HAS_MODERATOR, LABEL_HAS_MEMBER))) + .where(HBaseFilters.labelIn(LABEL_HAS_MODERATOR, LABEL_HAS_MEMBER))) .readRemainsAndClose(); List vertexResult = socialNetworkStore.getVertexSpace( Query.elements() .fromAll() - .where(new HBaseLabelIn<>(LABEL_TAG, LABEL_FORUM))) + .where(HBaseFilters.labelIn(LABEL_TAG, LABEL_FORUM).negate())) .readRemainsAndClose(); validateEPGMElementCollections(graphHeads, graphHeadResult); @@ -440,7 +570,7 @@ public void testGetElementSpaceWithLabelRegPredicate() throws IOException { List edges = Lists.newArrayList(getSocialEdges()) .stream() - .filter(e -> PATTERN_EDGE.matcher(e.getLabel()).matches()) + .filter(e -> !PATTERN_EDGE.matcher(e.getLabel()).matches()) .collect(Collectors.toList()); List vertices = Lists.newArrayList(getSocialVertices()) @@ -452,19 +582,19 @@ public void testGetElementSpaceWithLabelRegPredicate() throws IOException { List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() .fromAll() - .where(new HBaseLabelReg<>(PATTERN_GRAPH))) + .where(HBaseFilters.labelReg(PATTERN_GRAPH))) .readRemainsAndClose(); List edgeResult = socialNetworkStore.getEdgeSpace( Query.elements() .fromAll() - .where(new HBaseLabelReg<>(PATTERN_EDGE))) + .where(HBaseFilters.labelReg(PATTERN_EDGE).negate())) .readRemainsAndClose(); List vertexResult = socialNetworkStore.getVertexSpace( Query.elements() .fromAll() - .where(new HBaseLabelReg<>(PATTERN_VERTEX))) + .where(HBaseFilters.labelReg(PATTERN_VERTEX))) .readRemainsAndClose(); validateEPGMElementCollections(graphHeads, graphHeadResult); @@ -473,84 +603,235 @@ public void testGetElementSpaceWithLabelRegPredicate() throws IOException { } /** - * Test the getVertexSpace() method with an id filter predicate + * Test the getGraphSpace(), getVertexSpace() and getEdgeSpace() method + * with the {@link HBasePropEquals} predicate */ @Test - public void testGetVertexSpaceWithIdPredicate() throws IOException { - // Fetch all vertices from gdl file - List vertices = Lists.newArrayList(getSocialVertices()); - // Select only a subset - vertices = vertices.subList(1, 5); + public void testGetElementSpaceWithPropEqualsPredicate() throws IOException { + // Create the expected graph elements + PropertyValue propertyValueVertexCount = PropertyValue.create(3); + PropertyValue propertyValueSince = PropertyValue.create(2013); + PropertyValue propertyValueCity = PropertyValue.create("Leipzig"); - // Extract the vertex ids - GradoopIdSet ids = GradoopIdSet.fromExisting(vertices.stream() - .map(EPGMIdentifiable::getId) - .collect(Collectors.toList())); - // Query with the extracted ids - List queryResult = socialNetworkStore.getVertexSpace( + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + .filter(g -> g.hasProperty(PROP_VERTEX_COUNT)) + .filter(g -> g.getPropertyValue(PROP_VERTEX_COUNT).equals(propertyValueVertexCount)) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + .filter(e -> e.hasProperty(PROP_SINCE)) + .filter(e -> e.getPropertyValue(PROP_SINCE).equals(propertyValueSince)) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + .filter(v -> v.hasProperty(PROP_CITY)) + .filter(v -> v.getPropertyValue(PROP_CITY).equals(propertyValueCity)) + .collect(Collectors.toList()); + + // Query the store + List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() - .fromSets(ids) - .noFilter()) + .fromAll() + .where(HBaseFilters.propEquals(PROP_VERTEX_COUNT, propertyValueVertexCount))) .readRemainsAndClose(); - validateEPGMElementCollections(vertices, queryResult); + List edgeResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propEquals(PROP_SINCE, propertyValueSince))) + .readRemainsAndClose(); + + List vertexResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propEquals(PROP_CITY, propertyValueCity))) + .readRemainsAndClose(); + + validateEPGMElementCollections(graphHeads, graphHeadResult); + validateEPGMElementCollections(vertices, vertexResult); + validateEPGMElementCollections(edges, edgeResult); } /** - * Test the getVertexSpace() method without an id filter predicate + * Test the getGraphSpace(), getVertexSpace() and getEdgeSpace() method + * with the {@link HBasePropLargerThan} predicate */ @Test - public void testGetVertexSpaceWithoutIdPredicate() throws IOException { - // Fetch all vertices from gdl file - List vertices = Lists.newArrayList(getSocialVertices()); - // Query the graph store with an empty predicate - List queryResult = socialNetworkStore.getVertexSpace( + public void testGetElementSpaceWithPropLargerThanPredicate() throws IOException { + // Create the expected graph elements + PropertyValue propertyValueVertexCount = PropertyValue.create(3); + PropertyValue propertyValueSince = PropertyValue.create(2014); + PropertyValue propertyValueAge = PropertyValue.create(30); + + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + // graph with property "vertexCount" and value >= 3 + .filter(g -> g.hasProperty(PROP_VERTEX_COUNT)) + .filter(g -> g.getPropertyValue(PROP_VERTEX_COUNT).compareTo(propertyValueVertexCount) >= 0) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + // edge with property "since" and value > 2014 + .filter(e -> e.hasProperty(PROP_SINCE)) + .filter(e -> e.getPropertyValue(PROP_SINCE).compareTo(propertyValueSince) > 0) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + // vertex with property "age" and value > 30 + .filter(v -> v.hasProperty(PROP_AGE)) + .filter(v -> v.getPropertyValue(PROP_AGE).compareTo(propertyValueAge) > 0) + .collect(Collectors.toList()); + + // Query the store + List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() .fromAll() - .noFilter()) + .where(HBaseFilters.propLargerThan(PROP_VERTEX_COUNT, + propertyValueVertexCount, true))) .readRemainsAndClose(); - validateEPGMElementCollections(vertices, queryResult); + List edgeResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propLargerThan(PROP_SINCE, propertyValueSince, false))) + .readRemainsAndClose(); + + List vertexResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propLargerThan(PROP_AGE, propertyValueAge, false))) + .readRemainsAndClose(); + + validateEPGMElementCollections(graphHeads, graphHeadResult); + validateEPGMElementCollections(vertices, vertexResult); + validateEPGMElementCollections(edges, edgeResult); } /** - * Test the getEdgeSpace() method with an id filter predicate + * Test the getGraphSpace(), getVertexSpace() and getEdgeSpace() method + * with the {@link HBasePropReg} predicate */ @Test - public void testGetEdgeSpaceWithIdPredicate() throws IOException { - // Fetch all edges from gdl file - List edges = Lists.newArrayList(getSocialEdges()); - // Select only a subset - edges = edges.subList(3, 8); - // Extract the edge ids - GradoopIdSet ids = GradoopIdSet.fromExisting(edges.stream() - .map(EPGMIdentifiable::getId) - .collect(Collectors.toList())); - // Query with the extracted ids - List queryResult = socialNetworkStore.getEdgeSpace( + public void testGetElementSpaceWithPropRegPredicate() throws IOException { + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + // graph with property "name" and value matches regex ".*doop$" + .filter(g -> g.hasProperty(PROP_INTEREST)) + .filter(g -> g.getPropertyValue(PROP_INTEREST).getString() + .matches(PATTERN_GRAPH_PROP.pattern())) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + // edge with property "status" and value matches regex "^start..$" + .filter(e -> e.hasProperty(PROP_STATUS)) + .filter(e -> e.getPropertyValue(PROP_STATUS).getString().matches(PATTERN_EDGE_PROP.pattern())) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + // vertex with property "name" and value matches regex ".*ve$" + .filter(v -> v.hasProperty(PROP_NAME)) + .filter(v -> v.getPropertyValue(PROP_NAME).getString().matches(PATTERN_VERTEX_PROP.pattern())) + .collect(Collectors.toList()); + + // Query the store + List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() - .fromSets(ids) - .noFilter()) + .fromAll() + .where(HBaseFilters.propReg(PROP_INTEREST, PATTERN_GRAPH_PROP))) .readRemainsAndClose(); - validateEPGMElementCollections(edges, queryResult); + List edgeResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propReg(PROP_STATUS, PATTERN_EDGE_PROP))) + .readRemainsAndClose(); + + List vertexResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromAll() + .where(HBaseFilters.propReg(PROP_NAME, PATTERN_VERTEX_PROP))) + .readRemainsAndClose(); + + assertEquals(1, graphHeadResult.size()); + assertEquals(2, edgeResult.size()); + assertEquals(2, vertexResult.size()); + + validateEPGMElementCollections(graphHeads, graphHeadResult); + validateEPGMElementCollections(vertices, vertexResult); + validateEPGMElementCollections(edges, edgeResult); } /** - * Test the getEdgeSpace() method without an id filter predicate + * Test the getGraphSpace(), getVertexSpace() and getEdgeSpace() method + * with complex predicates */ @Test - public void testGetEdgeSpaceWithoutIdPredicate() throws IOException { - // Fetch all edges from gdl file - List edges = Lists.newArrayList(getSocialEdges()); - // Query the graph store with an empty predicate - List queryResult = socialNetworkStore.getEdgeSpace( + public void testGetElementSpaceWithChainedPredicates() throws IOException { + // Extract parts of social graph to filter for + List graphHeads = getSocialGraphHeads() + .stream() + .filter(g -> g.getLabel().equals("Community")) + .filter(g -> g.getPropertyValue(PROP_INTEREST).getString().equals("Hadoop") || + g.getPropertyValue(PROP_INTEREST).getString().equals("Graphs")) + .collect(Collectors.toList()); + + List edges = getSocialEdges() + .stream() + .filter(e -> e.getLabel().matches(PATTERN_EDGE.pattern()) || + (e.hasProperty(PROP_SINCE) && e.getPropertyValue(PROP_SINCE).getInt() < 2015)) + .collect(Collectors.toList()); + + List vertices = getSocialVertices() + .stream() + .filter(v -> v.getLabel().equals("Person")) + .collect(Collectors.toList()) + .subList(1, 4); + + // Query the store + List graphHeadResult = socialNetworkStore.getGraphSpace( Query.elements() .fromAll() - .noFilter()) + .where(HBaseFilters.labelIn("Community") + .and(HBaseFilters.propEquals(PROP_INTEREST, "Hadoop") + .or(HBaseFilters.propEquals(PROP_INTEREST, "Graphs"))))) .readRemainsAndClose(); - validateEPGMElementCollections(edges, queryResult); + List edgeResult = socialNetworkStore.getEdgeSpace( + Query.elements() + .fromAll() + // WHERE edge.label LIKE '^has.*$' OR edge.since < 2015 + .where(HBaseFilters.labelReg(PATTERN_EDGE) + .or(HBaseFilters.propLargerThan(PROP_SINCE, 2015, true).negate()))) + .readRemainsAndClose(); + + final HBaseElementFilter vertexFilter = HBaseFilters.labelIn("Person") + .and(HBaseFilters.propEquals(PROP_NAME, vertices.get(0).getPropertyValue("name")) + .or(HBaseFilters.propEquals(PROP_NAME, vertices.get(1).getPropertyValue("name")) + .or(HBaseFilters.propEquals(PROP_NAME, vertices.get(2).getPropertyValue("name"))))); + + List vertexResult = socialNetworkStore.getVertexSpace( + Query.elements() + .fromAll() + .where(vertexFilter)) + .readRemainsAndClose(); + + assertEquals(2, graphHeadResult.size()); + assertEquals(21, edgeResult.size()); + assertEquals(3, vertexResult.size()); + + validateEPGMElementCollections(graphHeads, graphHeadResult); + validateEPGMElementCollections(vertices, vertexResult); + validateEPGMElementCollections(edges, edgeResult); } private AsciiGraphLoader diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilterTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilterTest.java deleted file mode 100644 index 5b28cf13a12e..000000000000 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/api/HBaseElementFilterTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2014 - 2018 Leipzig University (Database Research Group) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -package org.gradoop.storage.impl.hbase.filter.api; - -import org.apache.commons.lang.NotImplementedException; -import org.apache.hadoop.hbase.filter.Filter; -import org.apache.hadoop.hbase.filter.FilterList; -import org.gradoop.common.model.api.entities.EPGMElement; -import org.gradoop.common.model.impl.pojo.Edge; -import org.junit.Test; - -import javax.annotation.Nonnull; - -/** - * Test class for the {@link HBaseElementFilter} interface - */ -public class HBaseElementFilterTest { - - /** - * Test that calling the 'or' function of an HBaseElementFilter instance throws the - * expected NotImplementedException. - */ - @Test(expected = NotImplementedException.class) - public void testElementFilterOr() { - DummyElementFilter filter = new DummyElementFilter<>(); - DummyElementFilter anotherFilter = new DummyElementFilter<>(); - - filter.or(anotherFilter); - } - - /** - * Test that calling the 'and' function of an HBaseElementFilter instance throws the - * expected NotImplementedException. - */ - @Test(expected = NotImplementedException.class) - public void testElementFilterAnd() { - DummyElementFilter filter = new DummyElementFilter<>(); - DummyElementFilter anotherFilter = new DummyElementFilter<>(); - - filter.and(anotherFilter); - } - - /** - * Test that calling the 'negate' function of an HBaseElementFilter instance throws the - * expected NotImplementedException. - */ - @Test(expected = NotImplementedException.class) - public void testElementFilterNegate() { - DummyElementFilter filter = new DummyElementFilter<>(); - - filter.negate(); - } - - /** - * A dummy class implements the interface to test - * - * @param a EPGM graph element class - */ - public class DummyElementFilter implements HBaseElementFilter { - @Nonnull - @Override - public Filter toHBaseFilter() { - return new FilterList(); - } - } -} diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/io/HBaseDataSinkSourceTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/io/HBaseDataSinkSourceTest.java index 7301629bf6b1..21f25bd2a69b 100644 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/io/HBaseDataSinkSourceTest.java +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/io/HBaseDataSinkSourceTest.java @@ -24,14 +24,20 @@ import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.PropertyValue; import org.gradoop.flink.model.GradoopFlinkTestBase; import org.gradoop.flink.model.api.epgm.GraphCollection; import org.gradoop.flink.util.FlinkAsciiGraphLoader; import org.gradoop.flink.util.GradoopFlinkConfig; import org.gradoop.storage.common.predicate.query.Query; import org.gradoop.storage.impl.hbase.HBaseEPGMStore; -import org.gradoop.storage.impl.hbase.filter.impl.HBaseLabelIn; -import org.gradoop.storage.impl.hbase.filter.impl.HBaseLabelReg; +import org.gradoop.storage.impl.hbase.predicate.filter.api.HBaseElementFilter; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelIn; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBaseLabelReg; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropEquals; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropLargerThan; +import org.gradoop.storage.impl.hbase.predicate.filter.impl.HBasePropReg; +import org.gradoop.storage.utils.HBaseFilters; import org.junit.After; import org.junit.Before; import org.junit.FixMethodOrder; @@ -45,9 +51,32 @@ import java.util.List; import java.util.stream.Collectors; -import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.*; import static org.gradoop.common.GradoopTestUtils.validateEPGMElementCollections; import static org.gradoop.common.GradoopTestUtils.validateEPGMGraphElementCollections; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.LABEL_FORUM; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.LABEL_HAS_MEMBER; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.LABEL_HAS_MODERATOR; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.LABEL_TAG; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_EDGE; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_EDGE_PROP; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_GRAPH; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_GRAPH_PROP; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_VERTEX; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PATTERN_VERTEX_PROP; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_AGE; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_CITY; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_INTEREST; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_NAME; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_SINCE; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_STATUS; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.PROP_VERTEX_COUNT; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.createEmptyEPGMStore; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.getSocialEdges; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.getSocialGraphHeads; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.getSocialVertices; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.openEPGMStore; +import static org.gradoop.storage.impl.hbase.GradoopHBaseTestBase.writeSocialGraphToStore; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** @@ -72,7 +101,7 @@ public class HBaseDataSinkSourceTest extends GradoopFlinkTestBase { */ @Before public void setUp() throws IOException { - epgmStore = openEPGMStore(getExecutionEnvironment(), "HBaseDataSinkSourceTest."); + epgmStore = openEPGMStore("HBaseDataSinkSourceTest."); writeSocialGraphToStore(epgmStore); } @@ -91,8 +120,10 @@ public void tearDown() throws IOException { */ @Test public void testReadFromSource() throws Exception { + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + // read social graph from HBase via EPGMDatabase - GraphCollection collection = new HBaseDataSource(epgmStore).getGraphCollection(); + GraphCollection collection = new HBaseDataSource(epgmStore, flinkConfig).getGraphCollection(); Collection loadedGraphHeads = Lists.newArrayList(); Collection loadedVertices = Lists.newArrayList(); @@ -116,8 +147,10 @@ public void testReadFromSource() throws Exception { */ @Test public void testReadFromSourceWithEmptyPredicates() throws Exception { + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + // Define HBase source - HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); // Apply empty graph predicate hBaseDataSource = hBaseDataSource.applyGraphPredicate(Query.elements().fromAll().noFilter()); @@ -162,7 +195,8 @@ public void testReadWithGraphIdPredicate() throws Throwable { testGraphs.stream().map(EPGMIdentifiable::getId).collect(Collectors.toList()) ); - HBaseDataSource source = new HBaseDataSource(epgmStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource source = new HBaseDataSource(epgmStore, flinkConfig); source = source.applyGraphPredicate( Query.elements() @@ -196,7 +230,8 @@ public void testReadWithVertexIdPredicate() throws Throwable { testVertices.stream().map(EPGMIdentifiable::getId).collect(Collectors.toList()) ); - HBaseDataSource source = new HBaseDataSource(epgmStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource source = new HBaseDataSource(epgmStore, flinkConfig); // Apply Vertex-Id predicate source = source.applyVertexPredicate( @@ -231,7 +266,8 @@ public void testReadWithEdgeIdPredicate() throws Throwable { testEdges.stream().map(EPGMIdentifiable::getId).collect(Collectors.toList()) ); - HBaseDataSource source = new HBaseDataSource(epgmStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource source = new HBaseDataSource(epgmStore, flinkConfig); // Apply Edge-Id predicate source = source.applyEdgePredicate( @@ -278,21 +314,22 @@ public void testReadWithLabelInPredicate() throws Exception { .collect(Collectors.toList()); // Define HBase source - HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); // Apply graph predicate hBaseDataSource = hBaseDataSource.applyGraphPredicate( - Query.elements().fromAll().where(new HBaseLabelIn<>(LABEL_FORUM)) + Query.elements().fromAll().where(HBaseFilters.labelIn(LABEL_FORUM)) ); // Apply edge predicate hBaseDataSource = hBaseDataSource.applyEdgePredicate( - Query.elements().fromAll().where(new HBaseLabelIn<>(LABEL_HAS_MODERATOR, LABEL_HAS_MEMBER)) + Query.elements().fromAll().where(HBaseFilters.labelIn(LABEL_HAS_MODERATOR, LABEL_HAS_MEMBER)) ); // Apply vertex predicate hBaseDataSource = hBaseDataSource.applyVertexPredicate( - Query.elements().fromAll().where(new HBaseLabelIn<>(LABEL_TAG, LABEL_FORUM)) + Query.elements().fromAll().where(HBaseFilters.labelIn(LABEL_TAG, LABEL_FORUM)) ); assertTrue(hBaseDataSource.isFilterPushedDown()); @@ -333,22 +370,81 @@ public void testReadWithLabelRegPredicate() throws Exception { .collect(Collectors.toList()); // Define HBase source - HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); // Apply empty graph predicate hBaseDataSource = hBaseDataSource.applyGraphPredicate( - Query.elements().fromAll().where(new HBaseLabelReg<>(PATTERN_GRAPH)) - ); + Query.elements().fromAll().where(HBaseFilters.labelReg(PATTERN_GRAPH))); // Apply empty edge predicate hBaseDataSource = hBaseDataSource.applyEdgePredicate( - Query.elements().fromAll().where(new HBaseLabelReg<>(PATTERN_EDGE)) - ); + Query.elements().fromAll().where(HBaseFilters.labelReg(PATTERN_EDGE))); // Apply empty vertex predicate hBaseDataSource = hBaseDataSource.applyVertexPredicate( - Query.elements().fromAll().where(new HBaseLabelReg<>(PATTERN_VERTEX)) - ); + Query.elements().fromAll().where(HBaseFilters.labelReg(PATTERN_VERTEX))); + + assertTrue(hBaseDataSource.isFilterPushedDown()); + + GraphCollection graphCollection = hBaseDataSource.getGraphCollection(); + + Collection loadedGraphHeads = graphCollection.getGraphHeads().collect(); + Collection loadedVertices = graphCollection.getVertices().collect(); + Collection loadedEdges = graphCollection.getEdges().collect(); + + validateEPGMElementCollections(graphHeads, loadedGraphHeads); + validateEPGMElementCollections(vertices, loadedVertices); + validateEPGMGraphElementCollections(vertices, loadedVertices); + validateEPGMElementCollections(edges, loadedEdges); + validateEPGMGraphElementCollections(edges, loadedEdges); + } + + /** + * Test reading a graph collection from {@link HBaseDataSource} + * with a {@link HBasePropEquals} predicate on each graph element + */ + @Test + public void testReadWithPropEqualsPredicate() throws Exception { + PropertyValue propertyValueVertexCount = PropertyValue.create(3); + PropertyValue propertyValueSince = PropertyValue.create(2013); + PropertyValue propertyValueCity = PropertyValue.create("Leipzig"); + + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + .filter(g -> g.hasProperty(PROP_VERTEX_COUNT)) + .filter(g -> g.getPropertyValue(PROP_VERTEX_COUNT).equals(propertyValueVertexCount)) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + .filter(e -> e.hasProperty(PROP_SINCE)) + .filter(e -> e.getPropertyValue(PROP_SINCE).equals(propertyValueSince)) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + .filter(v -> v.hasProperty(PROP_CITY)) + .filter(v -> v.getPropertyValue(PROP_CITY).equals(propertyValueCity)) + .collect(Collectors.toList()); + + // Define HBase source + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); + + // Apply graph predicate + hBaseDataSource = hBaseDataSource.applyGraphPredicate( + Query.elements().fromAll() + .where(HBaseFilters.propEquals(PROP_VERTEX_COUNT, propertyValueVertexCount))); + + // Apply edge predicate + hBaseDataSource = hBaseDataSource.applyEdgePredicate( + Query.elements().fromAll().where(HBaseFilters.propEquals(PROP_SINCE, propertyValueSince))); + + // Apply vertex predicate + hBaseDataSource = hBaseDataSource.applyVertexPredicate( + Query.elements().fromAll().where(HBaseFilters.propEquals(PROP_CITY, propertyValueCity))); assertTrue(hBaseDataSource.isFilterPushedDown()); @@ -365,16 +461,221 @@ public void testReadWithLabelRegPredicate() throws Exception { validateEPGMGraphElementCollections(edges, loadedEdges); } + /** + * Test reading a graph collection from {@link HBaseDataSource} + * with a {@link HBasePropLargerThan} predicate on each graph element + */ + @Test + public void testReadWithPropLargerThanPredicate() throws Exception { + PropertyValue propertyValueVertexCount = PropertyValue.create(3); + PropertyValue propertyValueSince = PropertyValue.create(2014); + PropertyValue propertyValueAge = PropertyValue.create(30); + + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + // graph with property "vertexCount" and value >= 3 + .filter(g -> g.hasProperty(PROP_VERTEX_COUNT)) + .filter(g -> g.getPropertyValue(PROP_VERTEX_COUNT).compareTo(propertyValueVertexCount) >= 0) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + // edge with property "since" and value > 2014 + .filter(e -> e.hasProperty(PROP_SINCE)) + .filter(e -> e.getPropertyValue(PROP_SINCE).compareTo(propertyValueSince) > 0) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + // vertex with property "age" and value > 30 + .filter(v -> v.hasProperty(PROP_AGE)) + .filter(v -> v.getPropertyValue(PROP_AGE).compareTo(propertyValueAge) > 0) + .collect(Collectors.toList()); + + // Define HBase source + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); + + // Apply graph predicate + hBaseDataSource = hBaseDataSource.applyGraphPredicate( + Query.elements().fromAll() + .where(HBaseFilters.propLargerThan(PROP_VERTEX_COUNT, propertyValueVertexCount, + true))); + + // Apply edge predicate + hBaseDataSource = hBaseDataSource.applyEdgePredicate( + Query.elements().fromAll() + .where(HBaseFilters.propLargerThan(PROP_SINCE, propertyValueSince, false))); + + // Apply vertex predicate + hBaseDataSource = hBaseDataSource.applyVertexPredicate( + Query.elements().fromAll() + .where(HBaseFilters.propLargerThan(PROP_AGE, propertyValueAge, false))); + + assertTrue(hBaseDataSource.isFilterPushedDown()); + + GraphCollection graphCollection = hBaseDataSource.getGraphCollection(); + + Collection loadedGraphHeads = graphCollection.getGraphHeads().collect(); + Collection loadedVertices = graphCollection.getVertices().collect(); + Collection loadedEdges = graphCollection.getEdges().collect(); + + validateEPGMElementCollections(graphHeads, loadedGraphHeads); + validateEPGMElementCollections(vertices, loadedVertices); + validateEPGMGraphElementCollections(vertices, loadedVertices); + validateEPGMElementCollections(edges, loadedEdges); + validateEPGMGraphElementCollections(edges, loadedEdges); + } + + /** + * Test reading a graph collection from {@link HBaseDataSource} + * with a {@link HBasePropReg} predicate on each graph element + */ + @Test + public void testReadWithPropRegPredicate() throws Exception { + // Extract parts of social graph to filter for + List graphHeads = Lists.newArrayList(getSocialGraphHeads()) + .stream() + // graph with property "name" and value matches regex ".*doop$" + .filter(g -> g.hasProperty(PROP_INTEREST)) + .filter(g -> g.getPropertyValue(PROP_INTEREST).getString() + .matches(PATTERN_GRAPH_PROP.pattern())) + .collect(Collectors.toList()); + + List edges = Lists.newArrayList(getSocialEdges()) + .stream() + // edge with property "status" and value matches regex "^start..$" + .filter(e -> e.hasProperty(PROP_STATUS)) + .filter(e -> e.getPropertyValue(PROP_STATUS).getString().matches(PATTERN_EDGE_PROP.pattern())) + .collect(Collectors.toList()); + + List vertices = Lists.newArrayList(getSocialVertices()) + .stream() + // vertex with property "name" and value matches regex ".*ve$" + .filter(v -> v.hasProperty(PROP_NAME)) + .filter(v -> v.getPropertyValue(PROP_NAME).getString().matches(PATTERN_VERTEX_PROP.pattern())) + .collect(Collectors.toList()); + + // Define HBase source + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); + + // Apply graph predicate + hBaseDataSource = hBaseDataSource.applyGraphPredicate( + Query.elements().fromAll() + .where(HBaseFilters.propReg(PROP_INTEREST, PATTERN_GRAPH_PROP))); + + // Apply edge predicate + hBaseDataSource = hBaseDataSource.applyEdgePredicate( + Query.elements().fromAll() + .where(HBaseFilters.propReg(PROP_STATUS, PATTERN_EDGE_PROP))); + + // Apply vertex predicate + hBaseDataSource = hBaseDataSource.applyVertexPredicate( + Query.elements().fromAll() + .where(HBaseFilters.propReg(PROP_NAME, PATTERN_VERTEX_PROP))); + + assertTrue(hBaseDataSource.isFilterPushedDown()); + + GraphCollection graphCollection = hBaseDataSource.getGraphCollection(); + + Collection loadedGraphHeads = graphCollection.getGraphHeads().collect(); + Collection loadedVertices = graphCollection.getVertices().collect(); + Collection loadedEdges = graphCollection.getEdges().collect(); + + assertEquals(1, loadedGraphHeads.size()); + assertEquals(2, loadedEdges.size()); + assertEquals(2, loadedVertices.size()); + + validateEPGMElementCollections(graphHeads, loadedGraphHeads); + validateEPGMElementCollections(vertices, loadedVertices); + validateEPGMGraphElementCollections(vertices, loadedVertices); + validateEPGMElementCollections(edges, loadedEdges); + validateEPGMGraphElementCollections(edges, loadedEdges); + } + + /** + * Test reading a graph collection from {@link HBaseDataSource} + * with logical chained predicates on each graph element + */ + @Test + public void testReadWithChainedPredicates() throws Exception { + // Extract parts of social graph to filter for + List graphHeads = getSocialGraphHeads() + .stream() + .filter(g -> g.getLabel().equals("Community")) + .filter(g -> !g.getPropertyValue(PROP_INTEREST).getString().equals("Hadoop") && + !g.getPropertyValue(PROP_INTEREST).getString().equals("Graphs")) + .collect(Collectors.toList()); + + List edges = getSocialEdges() + .stream() + .filter(e -> e.getLabel().matches(PATTERN_EDGE.pattern()) || + (e.hasProperty(PROP_SINCE) && e.getPropertyValue(PROP_SINCE).getInt() < 2015)) + .collect(Collectors.toList()); + + List vertices = getSocialVertices() + .stream() + .filter(v -> v.getLabel().equals("Person")) + .collect(Collectors.toList()) + .subList(1, 4); + + // Define HBase source + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + HBaseDataSource hBaseDataSource = new HBaseDataSource(epgmStore, flinkConfig); + + // Apply graph predicate + hBaseDataSource = hBaseDataSource.applyGraphPredicate( + Query.elements().fromAll() + // WHERE gh.label = "Community" AND NOT(gh.interest = "Hadoop" OR gh.interest = "Graphs") + .where(HBaseFilters.labelIn("Community") + .and(HBaseFilters.propEquals(PROP_INTEREST, "Hadoop") + .or(HBaseFilters.propEquals(PROP_INTEREST, "Graphs")).negate()))); + + // Apply edge predicate + hBaseDataSource = hBaseDataSource.applyEdgePredicate( + Query.elements().fromAll() + // WHERE edge.label LIKE '^has.*$' OR edge.since < 2015 + .where(HBaseFilters.labelReg(PATTERN_EDGE) + .or(HBaseFilters.propLargerThan(PROP_SINCE, 2015, true).negate()))); + + // Apply vertex predicate + final HBaseElementFilter vertexFilter = HBaseFilters.labelIn("Person") + .and(HBaseFilters.propEquals(PROP_NAME, vertices.get(0).getPropertyValue("name")) + .or(HBaseFilters.propEquals(PROP_NAME, vertices.get(1).getPropertyValue("name")) + .or(HBaseFilters.propEquals(PROP_NAME, vertices.get(2).getPropertyValue("name"))))); + + hBaseDataSource = hBaseDataSource.applyVertexPredicate( + Query.elements().fromAll() + .where(vertexFilter)); + + assertTrue(hBaseDataSource.isFilterPushedDown()); + + GraphCollection graphCollection = hBaseDataSource.getGraphCollection(); + + Collection loadedGraphHeads = graphCollection.getGraphHeads().collect(); + Collection loadedVertices = graphCollection.getVertices().collect(); + Collection loadedEdges = graphCollection.getEdges().collect(); + + assertEquals(1, loadedGraphHeads.size()); + assertEquals(21, loadedEdges.size()); + assertEquals(3, loadedVertices.size()); + + validateEPGMElementCollections(graphHeads, loadedGraphHeads); + validateEPGMElementCollections(vertices, loadedVertices); + validateEPGMGraphElementCollections(vertices, loadedVertices); + validateEPGMElementCollections(edges, loadedEdges); + validateEPGMGraphElementCollections(edges, loadedEdges); + } + /** * Test writing a graph to {@link HBaseDataSink} */ @Test public void testWriteToSink() throws Exception { // Create an empty store - HBaseEPGMStore epgmStore = createEmptyEPGMStore( - getExecutionEnvironment(), - "testWriteToSink" - ); + HBaseEPGMStore epgmStore = createEmptyEPGMStore("testWriteToSink"); FlinkAsciiGraphLoader loader = new FlinkAsciiGraphLoader(config); @@ -383,13 +684,14 @@ public void testWriteToSink() throws Exception { loader.initDatabaseFromStream(inputStream); - new HBaseDataSink(epgmStore).write(epgmStore - .getConfig() - .getGraphCollectionFactory() - .fromCollections( - loader.getGraphHeads(), - loader.getVertices(), - loader.getEdges())); + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + new HBaseDataSink(epgmStore, flinkConfig) + .write(flinkConfig + .getGraphCollectionFactory() + .fromCollections( + loader.getGraphHeads(), + loader.getVertices(), + loader.getEdges())); getExecutionEnvironment().execute(); @@ -428,13 +730,13 @@ public void testWriteToSink() throws Exception { @Test(expected = NotImplementedException.class) public void testWriteToSinkWithOverWrite() throws Exception { // Create an empty store - HBaseEPGMStore epgmStore = createEmptyEPGMStore(getExecutionEnvironment(), - "testWriteToSink"); + HBaseEPGMStore epgmStore = createEmptyEPGMStore("testWriteToSink"); - GraphCollection graphCollection = epgmStore.getConfig().getGraphCollectionFactory() + GradoopFlinkConfig flinkConfig = GradoopFlinkConfig.createConfig(getExecutionEnvironment()); + GraphCollection graphCollection = flinkConfig.getGraphCollectionFactory() .createEmptyCollection(); - (new HBaseDataSink(epgmStore)).write(graphCollection, true); + new HBaseDataSink(epgmStore, flinkConfig).write(graphCollection, true); getExecutionEnvironment().execute(); } diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelInTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelInTest.java similarity index 95% rename from gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelInTest.java rename to gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelInTest.java index 9824f1201c19..269beb270af5 100644 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelInTest.java +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelInTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.gradoop.storage.impl.hbase.filter.impl; +package org.gradoop.storage.impl.hbase.predicate.filter.impl; import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.filter.FilterList; @@ -54,6 +54,6 @@ public void testToHBaseFilter() { ); expectedFilterList.addFilter(valueFilter); } - assertEquals(expectedFilterList.toString(), edgeFilter.toHBaseFilter().toString()); + assertEquals(expectedFilterList.toString(), edgeFilter.toHBaseFilter(false).toString()); } } diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelRegTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelRegTest.java similarity index 95% rename from gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelRegTest.java rename to gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelRegTest.java index 0c7a09781233..be9f826214c5 100644 --- a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/filter/impl/HBaseLabelRegTest.java +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBaseLabelRegTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.gradoop.storage.impl.hbase.filter.impl; +package org.gradoop.storage.impl.hbase.predicate.filter.impl; import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.filter.Filter; @@ -48,6 +48,6 @@ public void testToHBaseFilter() { new RegexStringComparator(PATTERN_VERTEX.pattern()) ); - assertEquals(expectedFilter.toString(), vertexFilter.toHBaseFilter().toString()); + assertEquals(expectedFilter.toString(), vertexFilter.toHBaseFilter(false).toString()); } } diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEqualsTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEqualsTest.java new file mode 100644 index 000000000000..2e88f9fd223c --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropEqualsTest.java @@ -0,0 +1,127 @@ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.CompareFilter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; +import org.apache.hadoop.hbase.util.Bytes; +import org.gradoop.common.GradoopTestUtils; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.PropertyValue; +import org.gradoop.common.model.impl.properties.PropertyValueUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_TYPE; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_VALUE; +import static org.junit.Assert.assertEquals; + +/** + * Test class for {@link HBasePropEquals} + */ +@RunWith(Parameterized.class) +public class HBasePropEqualsTest { + + /** + * Property type + */ + private final String propertyType; + + /** + * Property key + */ + private final String propertyKey; + + /** + * Property value + */ + private final PropertyValue propertyValue; + + /** + * Constructor for parametrized test + * + * @param propertyKey property key to test + * @param value property value to test + */ + public HBasePropEqualsTest(String propertyKey, Object value) { + this.propertyKey = propertyKey; + this.propertyValue = PropertyValue.create(value); + this.propertyType = this.propertyValue.getType() == null ? + "null" : this.propertyValue.getType().toString(); + } + + /** + * Test the toHBaseFilter function + */ + @Test + public void testToHBaseFilter() { + + HBasePropEquals vertexFilter = new HBasePropEquals<>(propertyKey, propertyValue); + + FilterList expectedFilter = new FilterList(FilterList.Operator.MUST_PASS_ALL); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_VALUE), + Bytes.toBytesBinary(propertyKey), + CompareFilter.CompareOp.EQUAL, + PropertyValueUtils.Bytes.getRawBytesWithoutType(propertyValue)); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_TYPE), + Bytes.toBytesBinary(propertyKey), + CompareFilter.CompareOp.EQUAL, + PropertyValueUtils.Bytes.getTypeByte(propertyValue)); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + expectedFilter.addFilter(valueFilter); + expectedFilter.addFilter(typeFilter); + + assertEquals("Failed during filter comparison for type [" + propertyType + "].", + expectedFilter.toString(), vertexFilter.toHBaseFilter(false).toString()); + } + + /** + * Function to initiate the test parameters + * + * @return a collection containing the test parameters + */ + @Parameterized.Parameters + public static Collection properties() { + ArrayList intList = new ArrayList<>(); + intList.add(PropertyValue.create(1234)); + intList.add(PropertyValue.create(5678)); + + Map objectMap = new HashMap<>(); + objectMap.put(PropertyValue.create("a"), PropertyValue.create(12.345)); + objectMap.put(PropertyValue.create("b"), PropertyValue.create(67.89)); + + return Arrays.asList(new Object[][] { + {GradoopTestUtils.KEY_0, GradoopTestUtils.NULL_VAL_0}, + {GradoopTestUtils.KEY_1, GradoopTestUtils.BOOL_VAL_1}, + {GradoopTestUtils.KEY_2, GradoopTestUtils.INT_VAL_2}, + {GradoopTestUtils.KEY_3, GradoopTestUtils.LONG_VAL_3}, + {GradoopTestUtils.KEY_4, GradoopTestUtils.FLOAT_VAL_4}, + {GradoopTestUtils.KEY_5, GradoopTestUtils.DOUBLE_VAL_5}, + {GradoopTestUtils.KEY_6, GradoopTestUtils.STRING_VAL_6}, + {GradoopTestUtils.KEY_7, GradoopTestUtils.BIG_DECIMAL_VAL_7}, + {GradoopTestUtils.KEY_8, GradoopTestUtils.GRADOOP_ID_VAL_8}, + {GradoopTestUtils.KEY_9, objectMap}, + {GradoopTestUtils.KEY_a, intList}, + {GradoopTestUtils.KEY_b, GradoopTestUtils.DATE_VAL_b}, + {GradoopTestUtils.KEY_c, GradoopTestUtils.TIME_VAL_c}, + {GradoopTestUtils.KEY_d, GradoopTestUtils.DATETIME_VAL_d}, + {GradoopTestUtils.KEY_e, GradoopTestUtils.SHORT_VAL_e} + }); + } +} diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThanTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThanTest.java new file mode 100644 index 000000000000..8d65dcaef21c --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropLargerThanTest.java @@ -0,0 +1,135 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.BinaryComparator; +import org.apache.hadoop.hbase.filter.CompareFilter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; +import org.apache.hadoop.hbase.util.Bytes; +import org.gradoop.common.GradoopTestUtils; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.PropertyValue; +import org.gradoop.common.model.impl.properties.PropertyValueUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_TYPE; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_VALUE; +import static org.junit.Assert.assertEquals; + +/** + * Test class for {@link HBasePropLargerThan} + */ +@RunWith(Parameterized.class) +public class HBasePropLargerThanTest { + /** + * Property type + */ + private final String propertyType; + + /** + * Property key + */ + private final String propertyKey; + + /** + * Property value + */ + private final PropertyValue propertyValue; + + /** + * Flag if min value should be included + */ + private final boolean isInclude; + + /** + * Constructor for parametrized test + * + * @param propertyKey property key to test + * @param value property value to test + * @param isInclude flag if min value should be included + */ + public HBasePropLargerThanTest(String propertyKey, Object value, boolean isInclude) { + this.propertyKey = propertyKey; + this.propertyValue = PropertyValue.create(value); + this.isInclude = isInclude; + this.propertyType = this.propertyValue.getType() == null ? + "null" : this.propertyValue.getType().toString(); + } + + /** + * Test the toHBaseFilter function + */ + @Test + public void testToHBaseFilter() { + HBasePropLargerThan vertexFilter = + new HBasePropLargerThan<>(propertyKey, propertyValue, isInclude); + + FilterList expectedFilter = new FilterList(FilterList.Operator.MUST_PASS_ALL); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_VALUE), + Bytes.toBytesBinary(propertyKey), + isInclude ? CompareFilter.CompareOp.GREATER_OR_EQUAL : CompareFilter.CompareOp.GREATER, + new BinaryComparator(PropertyValueUtils.Bytes.getRawBytesWithoutType(propertyValue))); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_TYPE), + Bytes.toBytesBinary(propertyKey), + CompareFilter.CompareOp.EQUAL, + PropertyValueUtils.Bytes.getTypeByte(propertyValue)); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + expectedFilter.addFilter(valueFilter); + expectedFilter.addFilter(typeFilter); + + assertEquals("Failed during filter comparison for type [" + propertyType + "].", + expectedFilter.toString(), vertexFilter.toHBaseFilter(false).toString()); + } + + /** + * Function to initiate the test parameters + * + * @return a collection containing the test parameters + */ + @Parameterized.Parameters + public static Collection properties() { + return Arrays.asList(new Object[][] { + {GradoopTestUtils.KEY_2, GradoopTestUtils.INT_VAL_2, true}, + {GradoopTestUtils.KEY_3, GradoopTestUtils.LONG_VAL_3, true}, + {GradoopTestUtils.KEY_4, GradoopTestUtils.FLOAT_VAL_4, true}, + {GradoopTestUtils.KEY_5, GradoopTestUtils.DOUBLE_VAL_5, true}, + {GradoopTestUtils.KEY_7, GradoopTestUtils.BIG_DECIMAL_VAL_7, true}, + {GradoopTestUtils.KEY_e, GradoopTestUtils.SHORT_VAL_e, true}, + {GradoopTestUtils.KEY_2, GradoopTestUtils.INT_VAL_2, false}, + {GradoopTestUtils.KEY_3, GradoopTestUtils.LONG_VAL_3, false}, + {GradoopTestUtils.KEY_4, GradoopTestUtils.FLOAT_VAL_4, false}, + {GradoopTestUtils.KEY_5, GradoopTestUtils.DOUBLE_VAL_5, false}, + {GradoopTestUtils.KEY_7, GradoopTestUtils.BIG_DECIMAL_VAL_7, false}, + {GradoopTestUtils.KEY_e, GradoopTestUtils.SHORT_VAL_e, false}, + }); + } +} diff --git a/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropRegTest.java b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropRegTest.java new file mode 100644 index 000000000000..798dabf552df --- /dev/null +++ b/gradoop-store/gradoop-hbase/src/test/java/org/gradoop/storage/impl/hbase/predicate/filter/impl/HBasePropRegTest.java @@ -0,0 +1,73 @@ +/* + * Copyright © 2014 - 2018 Leipzig University (Database Research Group) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.gradoop.storage.impl.hbase.predicate.filter.impl; + +import org.apache.hadoop.hbase.filter.CompareFilter; +import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.RegexStringComparator; +import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; +import org.apache.hadoop.hbase.util.Bytes; +import org.gradoop.common.model.impl.pojo.Vertex; +import org.gradoop.common.model.impl.properties.PropertyValue; +import org.junit.Test; + +import java.util.regex.Pattern; + +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_TYPE; +import static org.gradoop.storage.impl.hbase.constants.HBaseConstants.CF_PROPERTY_VALUE; +import static org.junit.Assert.assertEquals; + +/** + * Test class for {@link HBasePropReg} + */ +public class HBasePropRegTest { + /** + * Test the toHBaseFilter function + */ + @Test + public void testToHBaseFilter() { + String key = "key"; + Pattern pattern = Pattern.compile("^FooBar.*$"); + + HBasePropReg vertexFilter = new HBasePropReg<>(key, pattern); + + FilterList expectedFilter = new FilterList(FilterList.Operator.MUST_PASS_ALL); + + SingleColumnValueFilter valueFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_VALUE), + Bytes.toBytesBinary(key), + CompareFilter.CompareOp.EQUAL, + new RegexStringComparator(pattern.pattern())); + + // Define that the entire row will be skipped if the column is not found + valueFilter.setFilterIfMissing(true); + + SingleColumnValueFilter typeFilter = new SingleColumnValueFilter( + Bytes.toBytesBinary(CF_PROPERTY_TYPE), + Bytes.toBytesBinary(key), + CompareFilter.CompareOp.EQUAL, + new byte[] {PropertyValue.TYPE_STRING}); + + // Define that the entire row will be skipped if the column is not found + typeFilter.setFilterIfMissing(true); + + expectedFilter.addFilter(typeFilter); + expectedFilter.addFilter(valueFilter); + + assertEquals("Failed during filter comparison for key [" + key + "].", + expectedFilter.toString(), vertexFilter.toHBaseFilter(false).toString()); + } +} diff --git a/gradoop-store/gradoop-hbase/src/test/resources/data/gdl/social_network.gdl b/gradoop-store/gradoop-hbase/src/test/resources/data/gdl/social_network.gdl index 3d1d056d14fd..d8b024249bfb 100644 --- a/gradoop-store/gradoop-hbase/src/test/resources/data/gdl/social_network.gdl +++ b/gradoop-store/gradoop-hbase/src/test/resources/data/gdl/social_network.gdl @@ -17,8 +17,8 @@ (frank)-[:hasInterest]->(hadoop) (dave)-[:hasInterest]->(hadoop) (gdbs)-[:hasModerator]->(alice) -(gdbs)-[:hasMember]->(alice) -(gdbs)-[:hasMember]->(bob) +(gdbs)-[:hasMember {status : "poweruser"}]->(alice) +(gdbs)-[:hasMember {status : "starter"}]->(bob) (databases)<-[ghtd:hasTag]-(gdbs)-[ghtg1:hasTag]->(graphs)<-[ghtg2:hasTag]-(gps)-[ghth:hasTag]->(hadoop) @@ -37,7 +37,7 @@ g2:Community {interest : "Graphs", vertexCount : 4} [ ] g3:Forum [ (gps)-[:hasModerator {since : 2013}]->(dave) - (gps)-[:hasMember]->(dave) + (gps)-[:hasMember {status : "starter"}]->(dave) (gps)-[:hasMember]->(carol)-[ckd]->(dave) ] diff --git a/gradoop-store/gradoop-hbase/src/test/resources/log4j-test.properties b/gradoop-store/gradoop-hbase/src/test/resources/log4j-test.properties index 727e8503836f..b02b2f0d3656 100644 --- a/gradoop-store/gradoop-hbase/src/test/resources/log4j-test.properties +++ b/gradoop-store/gradoop-hbase/src/test/resources/log4j-test.properties @@ -6,4 +6,4 @@ log4j.rootLogger=OFF, testlogger log4j.appender.testlogger=org.apache.log4j.ConsoleAppender log4j.appender.testlogger.target=System.err log4j.appender.testlogger.layout=org.apache.log4j.PatternLayout -log4j.appender.testlogger.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n \ No newline at end of file +log4j.appender.testlogger.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n diff --git a/gradoop-store/gradoop-store-api/pom.xml b/gradoop-store/gradoop-store-api/pom.xml index c5a5a95c98a6..ab76a5d41338 100644 --- a/gradoop-store/gradoop-store-api/pom.xml +++ b/gradoop-store/gradoop-store-api/pom.xml @@ -5,7 +5,7 @@ gradoop-store org.gradoop - 0.5.0-SNAPSHOT + 0.4.1 4.0.0 @@ -92,6 +92,10 @@ org.codehaus.mojo findbugs-maven-plugin + + org.jacoco + jacoco-maven-plugin + diff --git a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/api/EPGMGraphPredictableOutput.java b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/api/EPGMGraphPredictableOutput.java index 2a5109d5b5d4..14a93e8a98d7 100644 --- a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/api/EPGMGraphPredictableOutput.java +++ b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/api/EPGMGraphPredictableOutput.java @@ -44,19 +44,19 @@ public interface EPGMGraphPredictableOutput< @Nonnull @Override default ClosableIterator getGraphSpace(int cacheSize) throws IOException { - return getGraphSpace(null, DEFAULT_CACHE_SIZE); + return getGraphSpace(null, cacheSize); } @Nonnull @Override default ClosableIterator getVertexSpace(int cacheSize) throws IOException { - return getVertexSpace(null, DEFAULT_CACHE_SIZE); + return getVertexSpace(null, cacheSize); } @Nonnull @Override default ClosableIterator getEdgeSpace(int cacheSize) throws IOException { - return getEdgeSpace(null, DEFAULT_CACHE_SIZE); + return getEdgeSpace(null, cacheSize); } /** diff --git a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/config/GradoopStoreConfig.java b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/config/GradoopStoreConfig.java index baba2af2b83f..83f5aea841b5 100644 --- a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/config/GradoopStoreConfig.java +++ b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/config/GradoopStoreConfig.java @@ -15,94 +15,15 @@ */ package org.gradoop.storage.common.config; -import org.apache.flink.api.java.ExecutionEnvironment; import org.gradoop.storage.common.api.EPGMConfigProvider; -import org.gradoop.flink.model.api.layouts.GraphCollectionLayoutFactory; -import org.gradoop.flink.model.api.layouts.LogicalGraphLayoutFactory; -import org.gradoop.flink.model.impl.layouts.gve.GVECollectionLayoutFactory; -import org.gradoop.flink.model.impl.layouts.gve.GVEGraphLayoutFactory; -import org.gradoop.flink.util.GradoopFlinkConfig; -import javax.annotation.Nonnull; +import java.io.Serializable; /** * Definition of Gradoop Store Configuration * - * @param graph head factory - * @param vertex factory - * @param edge factory * @see EPGMConfigProvider store configuration holder */ -public abstract class GradoopStoreConfig extends GradoopFlinkConfig { - - /** - * Graph head factory. - */ - private final GF storeGraphHeadFactory; - /** - * Vertex factory. - */ - private final VF storeVertexFactory; - /** - * Edge factory. - */ - private final EF storeEdgeFactory; - - /** - * Creates a new Configuration. - * - * @param storeGraphHeadFactory store graph head factory - * @param storeVertexFactory store vertex factory - * @param storeEdgeFactory store edge factory - * @param env Flink {@link ExecutionEnvironment} - */ - protected GradoopStoreConfig( - @Nonnull GF storeGraphHeadFactory, - @Nonnull VF storeVertexFactory, - @Nonnull EF storeEdgeFactory, - @Nonnull ExecutionEnvironment env - ) { - this(storeGraphHeadFactory, - storeVertexFactory, - storeEdgeFactory, env, - new GVEGraphLayoutFactory(), - new GVECollectionLayoutFactory()); - } - - /** - * Creates a new Configuration with layout factory. - * - * @param storeGraphHeadFactory store graph head factory - * @param storeVertexFactory store vertex factory - * @param storeEdgeFactory store edge factory - * @param logicalGraphLayoutFactory logical graph layout factory - * @param graphCollectionLayoutFactory graph collection layout factory - * @param env Flink {@link ExecutionEnvironment} - */ - protected GradoopStoreConfig( - @Nonnull GF storeGraphHeadFactory, - @Nonnull VF storeVertexFactory, - @Nonnull EF storeEdgeFactory, - @Nonnull ExecutionEnvironment env, - @Nonnull LogicalGraphLayoutFactory logicalGraphLayoutFactory, - @Nonnull GraphCollectionLayoutFactory graphCollectionLayoutFactory - ) { - super(env, logicalGraphLayoutFactory, graphCollectionLayoutFactory); - this.storeGraphHeadFactory = storeGraphHeadFactory; - this.storeVertexFactory = storeVertexFactory; - this.storeEdgeFactory = storeEdgeFactory; - } - - public GF getStoreGraphHeadFactory() { - return storeGraphHeadFactory; - } - - public VF getStoreVertexFactory() { - return storeVertexFactory; - } - - public EF getStoreEdgeFactory() { - return storeEdgeFactory; - } +public interface GradoopStoreConfig extends Serializable { } diff --git a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/predicate/filter/impl/PropReg.java b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/predicate/filter/impl/PropReg.java index cf87f84f17e1..82c972d30f3d 100644 --- a/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/predicate/filter/impl/PropReg.java +++ b/gradoop-store/gradoop-store-api/src/main/java/org/gradoop/storage/common/predicate/filter/impl/PropReg.java @@ -43,7 +43,7 @@ public abstract class PropReg private final String key; /** - * label regex filter constructor + * Property regex filter constructor * * @param key property key * @param reg label regex diff --git a/gradoop-store/pom.xml b/gradoop-store/pom.xml index dc232027da24..7de6507f493c 100644 --- a/gradoop-store/pom.xml +++ b/gradoop-store/pom.xml @@ -5,7 +5,7 @@ gradoop-parent org.gradoop - 0.5.0-SNAPSHOT + 0.4.1 4.0.0 diff --git a/pom.xml b/pom.xml index ca7887cad087..c33ca4094911 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.gradoop gradoop-parent pom - 0.5.0-SNAPSHOT + 0.4.1 Gradoop Parent http://www.gradoop.org @@ -133,6 +133,7 @@ 1.2.17 log4j-test.properties + -Xmx1G -Dlog4j.configuration=${log4j.properties} 3.5.1 2.16 @@ -147,6 +148,7 @@ 1.6.7 3.4 1.1 + 0.8.1 @@ -420,7 +422,6 @@ **/*TestBase*.class - -Xmx1G -Dlog4j.configuration=${log4j.properties} @@ -468,6 +469,30 @@ + + org.jacoco + jacoco-maven-plugin + ${plugin.maven-jacoco.version} + + + pre-unit-test + + prepare-agent + + + + post-unit-test + + report + + + ${session.executionRootDirectory}/target/coverage-reports/${project.name} + ${project.name} + + + + +