• No results found

3.3 Results

3.3.4 Results: Soil carbon

Os principais artefatos de software que lidam diretamente com as abstrações de vértices e arestas nos sistemas Gust, GraphX e Giraph são, respectivamente, o componente GRAPH, a classe GraphX.Graph e a classe Giraph.Vertex.

No Giraph, onde o programador lida com um modelo de programação centrado nos vértices (“vertex-centric”), o desenvolvedor possui uma referência a objetos do tipo Vertex<I,V ,E>, onde: I é o tipo do identificador de vértice; V é o tipo do vértice; e E é o tipo da aresta. Vertex possui os métodos descritos na Tabela 17, onde os métodos correspondentes do componente GRAPH, do Gust, são apresentados (coluna à direita). É importante destacar que GRAPH é

usado pelo programador dentro de GUSTYFUNCTION, deixando todos os vértices acessíveis pelo

método vertexSet. De fato, Gust implementa o modelo Pregel sob uma visão centrada em grafo, enquanto Giraph adota o modelo clássico centrado em vértice. Entretanto, como estamos lidando com componentes e um contexto chave/valor MapReduce, cada chave TKey pode representar um vértice, sugerindo ao desenvolvedor a possibilidade de trabalhar com vértices individuais do grafo, ou seja, a forma clássica centrada em vértices suportada por Giraph.

Giraph.Vertex<I,V,E>: Gust.IGraphInstance<V, E, TV, TE>:

I=tipo de id do vértice TV=tipo id do vértice

V=tipo de dado do vértice V=componente Vertex para dados

E=tipo de dado de aresta E=componente Edge para dados

TE=instâncias de arestas geradas pelo padrão Factory

I getId(); foreach (TV v in vertexSet ())

V getValue(); getValue(v)

void setValue(V value); setValue(value)

int getNumEdges(); degreeOf(TV vertex), inDegreeOf(TV vertex), outDegreeOf(TV vertex) Iterable<Edge<I, E>> getEdges(); ICollection<TE> edgesOf(TV vertex)

void setEdges(Iterable<Edge<I, E>> edges); alterações individuais em arestas com setEdgeWeight(TE e) E getEdgeValue(I targetVertexId); getEdge(TV source, TV target).Weight

void setEdgeValue(I targetVertexId, E edgeValue); setEdgeWeight(TE edge)

Iterable<E> getAllEdgeValues(final I targetVertexId); foreach(TE e in edgesOf(TV vertex)) e.Weight void addEdge(Edge<I, E> edge); addEdge(TE e) e addEdge(TV source, TV target) void removeEdges(I targetVertexId); removeAllEdges(TV source, TV target)

Tabela 17 – Tabela comparativa de funcionalidades dos artefatos que manipulam grafos nos sistemas Gust e Giraph

var g = GraphX.Graph[V, E] var g = Gust.IGraphInstance<V, E, TV, TE> g.inDegrees.filter(v => v._1 == 10L).first g.inDegreeOf(10)

g.inDegrees.filter(v => v._2 < 2).foreach(println) foreach(int v in g.vertexSet().Where(v=>g.inDegreeOf(v)<2))Console.WriteLine(v+","+g.inDegreeOf(v)); g.outDegrees.filter(v => v._1 == 10L).first g.outDegreeOf(10)

g.outDegrees.filter(v => v._2 > 20).foreach(println) foreach(int v in g.vertexSet().Where(v=>g.outDegreeOf(v)>20))Console.WriteLine(v+","+g.outDegreeOf(v)); g.edges.filter(e => e.srcId > e.dstId).count g.edgeSet().Where (e => e.Source > e.Target).Count (); g.vertices.filter(v => v._1 > 262000L).count g.vertexSet().Where (v => v > 262000).Count ();

Tabela 18 – Tabela comparativa de algumas operações com artefatos que manipulam vértices e arestas nos sistemas Gust e GraphX

Em uma estratégia usando expressões de consultas, a Tabela 18 apresenta algumas pesquisas realizadas com a classe Graph do GraphX, bem como operações similares realizadas com o componente GRAPH do Gust, na segunda coluna. Nota-se a facilidade em realizar

filtragens em coleções de dados com o GraphX. Contudo, a linguagem C#, usada no Gust, também contempla operações similares, o que é possível através do componente .NET chamado System.Linq, que suporta a linguagem de consultas LINQ (Language Integrated Query), inspirada em SQL (Structured Query Language). Todavia, algumas diferenças estão na forma de lidar com a coleção ou tipo primitivo, como visto em seguida:

• no GraphX, as propriedades destacadas são: inDegrees, coleção de vértices e seus graus de entrada; outDegrees, coleção de vértices e seus graus de saída; vertices, coleções de vértices e seus valores; edges, coleções de arestas e seus valores;

• no Gust, os métodos inDegreeOf e outDegreeOf simplesmente retornam inteiros, en- quanto vertexSet e edgeSet respectivamente retornam as coleções de vértices e arestas da partição;

• Na primeira operação de GraphX, a coleção g.inDegrees.filter(v => v._1 == 10L).first, destaca um operador v com os atributos v._1 e v._2, os quais representam respectivamente

o identificador do vértice iterado na coleção e o seu grau de entrada. No exemplo, a busca é feita pelo vértice 10. No Gust, simplesmente é usado g.inDegreeOf(10);

• Na segunda operação, GraphX reduz bastante o código em relação ao Gust, justamente pelo acesso direto ao iterador foreach e porque o grau de entrada em GraphX é acessado por v._2, enquanto em Gust deve-se usar g.inDegreeOf(v) e um Console.WriteLine dentro do foreach. A operação imprime todos os vértices com grau de entrada menor que 2;

• Nas demais operações que não usam o iterador foreach(count), as formas de acesso são semelhantes, variando apenas a nomenclatura.

O estilo funcional, herdado da linguagem Scala, torna o GraphX, bem como o próprio Spark, uma ferramenta relativamente simples de se usar, especialmente para consultas de dados em um ambiente que pode ou não ser interativo com o usuário. No caso de um ambiente interativo, isso é feito através de um terminal, onde o operador insere códigos e imediatamente a resposta da execução ou consulta é obtida. No caso de um ambiente não interativo, o operador pode compilar o código e lançar um trabalho (job) que será paralelizado em um cluster. Em ambos os casos, a exigência de memória é crítica para cargas grandes. Neste aspecto, obtivemos resultados competitivos usando Gust, como serão vistos nas tabelas e gráficos de desempenho apresentados nas próximas seções deste capítulo. Avaliamos que essa vantagem está no uso de coleções otimizadas internamente aos componentes GRAPH e DATACONTAINER, que armazenam apenas

dados essenciais, que podem ser tipos primitivos. Além disso, para redução do consumo de memória, tem-se considerado vantajoso também o uso do próprio C#, que aceita o uso de tipos primitivos em variáveis de tipo na definição dos tipos genéricos de coleções, uma vez que preliminarmente comparamos implementações de GRAPHanálogas em Java, manipulando

Além disso, as consultas através da sintaxe LINQ podem ser melhor exploradas, com um maior número de coleções retornadas pelo componente Graph, através de novos métodos, também em trabalhos futuros. Na próxima seção, discutem-se os resultados experimentais de desempenho.

C S P B

PR SSSP TRI média efeito Sj

6 243.192 84.907 120.539 MET 8 229.253 83.798 121.978 143.900 -125.851 10 208.436 83.136 119.862 6 278.530 119.926 237.401 GUS 8 251.870 110.456 181.465 183.482 -86.269 10 213.270 108.098 150.322 LIV 6 428.173 197.057 424.319 GRA 8 380.927 209.790 360.767 319.871 50.121 10 353.116 196.852 327.843 6 438.393 65.188 1012.727 GIR 8 373.029 69.543 797.744 431.749 161.998 10 330.605 63.822 734.691 média 310.733 116.048 382.471 269.751 efeito Bi 40.982 -153.703 112.721 P média efeito Pk 6 304.196 34.445 8 264.218 -5.532 10 240.838 -28.913

Tabela 19 – Experimento fatorial LIV