All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tinkerpop.gremlin.process.computer.GraphComputerTest Maven / Gradle / Ivy

package com.tinkerpop.gremlin.process.computer;

import com.tinkerpop.gremlin.AbstractGremlinTest;
import com.tinkerpop.gremlin.LoadGraphWith;
import com.tinkerpop.gremlin.process.computer.lambda.LambdaMapReduce;
import com.tinkerpop.gremlin.process.computer.lambda.LambdaVertexProgram;
import com.tinkerpop.gremlin.structure.ExceptionCoverage;
import com.tinkerpop.gremlin.structure.FeatureRequirement;
import com.tinkerpop.gremlin.structure.Graph;
import com.tinkerpop.gremlin.structure.util.StringFactory;
import com.tinkerpop.gremlin.util.StreamFactory;
import org.junit.Test;

import java.util.Arrays;
import java.util.HashSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import static com.tinkerpop.gremlin.LoadGraphWith.GraphData.CLASSIC;
import static org.junit.Assert.*;

/**
 * @author Marko A. Rodriguez (http://markorodriguez.com)
 */
@ExceptionCoverage(exceptionClass = GraphComputer.Exceptions.class, methods = {
        "providedKeyIsNotASideEffectKey",
})
public class GraphComputerTest extends AbstractGremlinTest {

    @Test
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldHaveStandardStringRepresentation() {
        final GraphComputer computer = g.compute();
        assertEquals(StringFactory.computerString(computer), computer.toString());
    }

    @Test
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldNotAllowBadGraphComputers() {
        try {
            g.compute(BadGraphComputer.class);
            fail("Providing a bad graph computer class should fail");
        } catch (IllegalArgumentException e) {
            assertTrue(true);
        } catch (Exception e) {
            fail("Should provide an IllegalArgumentException");
        }
    }

    @Test
    @LoadGraphWith(CLASSIC)
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldNotAllowTheSameComputerToExecutedTwice() throws Exception {
        final GraphComputer computer = g.compute().program(identity());
        computer.submit().get(); // this should work as its the first run of the graph computer

        try {
            computer.submit(); // this should fail as the computer has already been executed
            fail("Using the same graph computer to compute again should not be possible");
        } catch (IllegalStateException e) {
            assertTrue(true);
        } catch (Exception e) {
            fail("Should yield an illegal state exception for graph computer being executed twice");
        }

        computer.program(identity());
        // test no rerun of graph computer
        try {
            computer.submit(); // this should fail as the computer has already been executed even through new program submitted
            fail("Using the same graph computer to compute again should not be possible");
        } catch (IllegalStateException e) {
            assertTrue(true);
        } catch (Exception e) {
            fail("Should yield an illegal state exception for graph computer being executed twice");
        }
    }

    @Test
    @LoadGraphWith(CLASSIC)
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldRequireRegisteringSideEffectKeys() throws Exception {
        try {
            g.compute().program(LambdaVertexProgram.build().
                    setup(s -> s.setIfAbsent("or", true)).
                    execute((v, m, s) -> {
                    }).
                    terminate(s -> s.getIteration() >= 2).create()).submit().get();
// TODO: GiraphAggregators and setup don't work right
//           fail("Should fail with an ExecutionException[IllegalArgumentException]");
        } catch (ExecutionException e) {
            assertEquals(IllegalArgumentException.class, e.getCause().getClass());
        } catch (Exception e) {
            fail("Should fail with an ExecutionException[IllegalArgumentException]: " + e);
        }
    }

    @Test
    @LoadGraphWith(CLASSIC)
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldAllowMapReduceWithNoVertexProgram() throws Exception {
        final ComputerResult results = g.compute().mapReduce(LambdaMapReduce.build()
                .map((v, e) -> v.property("age").ifPresent(age -> e.emit(MapReduce.NullObject.instance(), age)))
                .reduce((k, vv, e) -> e.emit(MapReduce.NullObject.instance(), StreamFactory.stream(vv).mapToInt(i -> i).sum()))
                .sideEffect(i -> i.next().getValue1())
                .sideEffectKey("ageSum").create())
                .submit().get();
        assertEquals(123, results.getSideEffects().get("ageSum").get());
    }

    @Test
    @LoadGraphWith(CLASSIC)
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldHaveConsistentSideEffectsAndExceptions() throws Exception {
        GraphComputer computer = g.compute();
        ComputerResult results = computer.program(LambdaVertexProgram.build().
                setup(s -> s.setIfAbsent("or", true)).
                execute((v, m, s) -> {
                    if (s.isInitialIteration()) {
                        v.property("nameLengthCounter", v.value("name").length());
                        s.incr("counter", v.value("name").length());
                        s.and("and", v.value("name").length() == 5);
                        s.or("or", false);
                    } else
                        v.property("nameLengthCounter", v.value("name").length() + v.value("nameLengthCounter"));
                }).
                terminate(s -> s.getIteration() >= 2).
                elementComputeKeys("nameLengthCounter", VertexProgram.KeyType.VARIABLE).
                sideEffectKeys(new HashSet<>(Arrays.asList("counter", "and", "or"))).create()).submit().get();
        assertEquals(1, results.getSideEffects().getIteration());
        assertEquals(3, results.getSideEffects().asMap().size());
        assertEquals(3, results.getSideEffects().keys().size());
        assertTrue(results.getSideEffects().keys().contains("counter"));
        assertTrue(results.getSideEffects().keys().contains("and"));
        assertTrue(results.getSideEffects().keys().contains("or"));

        assertEquals(Long.valueOf(28), results.getSideEffects().get("counter").get());
        assertFalse(results.getSideEffects().get("and").get());
// TODO for Giraph (has to do with setup and aggregator
// assertTrue(results.getSideEffects().get("or").get());
        assertFalse(results.getSideEffects().get("BAD").isPresent());
        assertEquals(Long.valueOf(6), results.getGraph().V().count().next());

        results.getGraph().V().forEach(v -> {
            assertTrue(v.property("nameLengthCounter").isPresent());
            assertEquals(Integer.valueOf(v.value("name").length() * 2), Integer.valueOf(v.value("nameLengthCounter")));
        });
    }

    @Test
    @LoadGraphWith(CLASSIC)
    @FeatureRequirement(featureClass = Graph.Features.GraphFeatures.class, feature = Graph.Features.GraphFeatures.FEATURE_COMPUTER)
    public void shouldSupportMultipleMapReduceJobs() throws Exception {
        final ComputerResult results = g.compute().program(LambdaVertexProgram.build()
                .execute((v, m, s) -> v.property("counter", s.isInitialIteration() ? 1 : v.value("counter") + 1))
                .terminate(s -> s.getIteration() > 9)
                .elementComputeKeys("counter", VertexProgram.KeyType.VARIABLE).create())
                .mapReduce(LambdaMapReduce.build()
                        .map((v, e) -> e.emit(MapReduce.NullObject.instance(), v.value("counter")))
                        .reduce((k, vv, e) -> {
                            int counter = 0;
                            while (vv.hasNext()) {
                                counter = counter + vv.next();
                            }
                            e.emit(MapReduce.NullObject.instance(), counter);

                        })
                        .sideEffect(i -> i.next().getValue1())
                        .sideEffectKey("a").create())
                .mapReduce(LambdaMapReduce.build()
                        .map((v, e) -> e.emit(MapReduce.NullObject.instance(), v.value("counter")))
                        .combine((k, vv, e) -> e.emit(MapReduce.NullObject.instance(), 1))
                        .reduce((k, vv, e) -> e.emit(MapReduce.NullObject.instance(), 1))
                        .sideEffect(i -> i.next().getValue1())
                        .sideEffectKey("b").create())
                .submit().get();


        assertEquals(60, results.getSideEffects().get("a").get());
        assertEquals(1, results.getSideEffects().get("b").get());
    }

    private static LambdaVertexProgram identity() {
        return LambdaVertexProgram.build().
                setup(s -> {
                }).
                execute((v, m, s) -> {
                }).
                terminate(s -> true).create();
    }

    class BadGraphComputer implements GraphComputer {
        public GraphComputer isolation(final Isolation isolation) {
            return null;
        }

        public GraphComputer program(final VertexProgram vertexProgram) {
            return null;
        }

        public GraphComputer mapReduce(final MapReduce mapReduce) {
            return null;
        }

        public Future submit() {
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy