Todos os produtos
Search
Central de documentação

MaxCompute:PageRank

Última atualização: Jun 26, 2026

O PageRank classifica vértices em um grafo direcionado por importância. Cada vértice representa uma página da web; cada aresta direcionada representa um link de uma página para outra. Páginas com mais links recebidos de outras páginas bem pontuadas obtêm pontuação maior — a mesma lógica que faz uma conta no Twitter seguida por usuários influentes ter classificação superior àquela seguida apenas por bots.

Funcionamento

No início de cada execução, todos os vértices recebem a mesma pontuação inicial: 1 / TotalNumVertices.

A cada superstep, cada vértice envia um voto aos vizinhos igual à sua pontuação atual dividida pelo grau de saída:

vote sent to neighbor = PageRank(j) / out_degree(j)

Ao final de cada superstep, todo vértice recalcula sua pontuação somando todos os votos recebidos e aplicando um fator de amortecimento:

PageRank(i) = 0.15 / TotalNumVertices + 0.85 × sum of incoming votes

O fator de amortecimento (0,85) modela a probabilidade de um usuário aleatório seguir um link em vez de saltar para uma página qualquer. O complemento (0,15) garante que cada vértice tenha uma pontuação base diferente de zero, mesmo sem arestas de entrada.

Por padrão, o algoritmo executa até 30 iterações (valor configurável).

Pré-requisitos

Antes de começar, verifique se você:

  • Configurou o ambiente de teste do MaxCompute Graph conforme descrito em Escrever um job Graph

  • Instalou o cliente MaxCompute

Execute o exemplo de PageRank

Etapa 1: Preparar o arquivo JAR

Coloque o arquivo graph-examples.jar na pasta data\resources, dentro do diretório bin do cliente MaxCompute.

Etapa 2: Crie as tabelas de entrada e saída

Execute as instruções SQL a seguir no cliente MaxCompute:

CREATE TABLE pagerank_in(vertex STRING, des_1 STRING, des_2 STRING);
CREATE TABLE pagerank_out(vertex_id STRING, vertex_value DOUBLE);

Na tabela pagerank_in, a primeira coluna contém os vértices de origem e as demais colunas representam os vértices de destino.

Etapa 3: Registrar o arquivo JAR

-- Use -f to overwrite if the resource already exists.
add jar data\resources\graph-examples.jar -f;

Etapa 4: Carregar os dados de teste

No diretório bin do cliente MaxCompute, carregue o arquivo data.txt na tabela pagerank_in:

tunnel upload data.txt pagerank_in;

O arquivo data.txt contém as seguintes arestas do grafo:

1,2,4
2,1,3
4,2,3
3,1,2

Cada linha traz um vértice de origem seguido pelos vértices de destino. Por exemplo, o vértice 1 possui arestas apontando para os vértices 2 e 4.

Etapa 5: Execute o job

jar -resources graph-examples.jar -classpath data\resources\graph-examples.jar
com.aliyun.odps.graph.PageRank pagerank_in pagerank_out

Parâmetros do job

Parâmetro

Descrição

Padrão

pagerank_in

Nome da tabela de entrada

pagerank_out

Nome da tabela de saída

Máximo de iterações (terceiro argumento opcional)

Quantidade máxima de supersteps antes da interrupção do job

30

Para substituir o número máximo de iterações, passe-o como terceiro argumento:

jar -resources graph-examples.jar -classpath data\resources\graph-examples.jar
com.aliyun.odps.graph.PageRank pagerank_in pagerank_out 50

Resultados esperados

Após a conclusão do job, consulte a tabela pagerank_out:

+------------+--------------------+
| vertex_id  | vertex_value       |
+------------+--------------------+
| 1          | 0.2781238395149928 |
| 2          | 0.3245614688676814 |
| 3          | 0.24161225195637787|
| 4          | 0.155702636559485  |
+------------+--------------------+

O vértice 2 apresenta a maior pontuação porque tanto o vértice 1 quanto o vértice 4 apontam para ele. Além disso, o próprio vértice 1 recebe links dos vértices 2 e 3. Já o vértice 4 tem a menor nota: apenas o vértice 1 aponta para ele, sem que nenhum vértice de alta pontuação lhe envie um voto significativo.

Para depuração local antes de enviar ao cluster, consulte Depuração local .

Código de exemplo

A implementação completa em Java aparece abaixo. As classes principais são:

  • PageRankVertex — define a lógica de computação por vértice

  • PageRankVertexReader — carrega a tabela de entrada e constrói o grafo

  • main — configura e executa o GraphJob

import java.io.IOException;

import org.apache.log4j.Logger;

import com.aliyun.odps.io.WritableRecord;
import com.aliyun.odps.graph.ComputeContext;
import com.aliyun.odps.graph.GraphJob;
import com.aliyun.odps.graph.GraphLoader;
import com.aliyun.odps.graph.MutationContext;
import com.aliyun.odps.graph.Vertex;
import com.aliyun.odps.graph.WorkerContext;
import com.aliyun.odps.io.DoubleWritable;
import com.aliyun.odps.io.LongWritable;
import com.aliyun.odps.io.NullWritable;
import com.aliyun.odps.data.TableInfo;
import com.aliyun.odps.io.Text;
import com.aliyun.odps.io.Writable;

public class PageRank {

  private final static Logger LOG = Logger.getLogger(PageRank.class);

  public static class PageRankVertex extends
      Vertex<Text, DoubleWritable, NullWritable, DoubleWritable> {

    @Override
    public void compute(
        ComputeContext<Text, DoubleWritable, NullWritable, DoubleWritable> context,
        Iterable<DoubleWritable> messages) throws IOException {
      if (context.getSuperstep() == 0) {
        // Superstep 0: initialize every vertex to 1 / TotalNumVertices
        setValue(new DoubleWritable(1.0 / context.getTotalNumVertices()));
      } else if (context.getSuperstep() >= 1) {
        // Superstep >= 1: sum incoming votes and apply the damping formula
        double sum = 0;
        for (DoubleWritable msg : messages) {
          sum += msg.get();
        }
        DoubleWritable vertexValue = new DoubleWritable(
            (0.15f / context.getTotalNumVertices()) + 0.85f * sum);
        setValue(vertexValue);
      }
      // Send this vertex's share of its score to each neighbor
      if (hasEdges()) {
        context.sendMessageToNeighbors(this, new DoubleWritable(getValue()
            .get() / getEdges().size()));
      }
    }

    @Override
    public void cleanup(
        WorkerContext<Text, DoubleWritable, NullWritable, DoubleWritable> context)
        throws IOException {
      // Write the final vertex ID and PageRank score to the output table
      context.write(getId(), getValue());
    }
  }

  public static class PageRankVertexReader extends
      GraphLoader<Text, DoubleWritable, NullWritable, DoubleWritable> {

    @Override
    public void load(
        LongWritable recordNum,
        WritableRecord record,
        MutationContext<Text, DoubleWritable, NullWritable, DoubleWritable> context)
        throws IOException {
      // Each table row becomes one vertex.
      // Column 0 is the source vertex; columns 1+ are destination vertices (edges).
      PageRankVertex vertex = new PageRankVertex();
      vertex.setValue(new DoubleWritable(0));
      vertex.setId((Text) record.get(0));
      System.out.println(record.get(0));

      for (int i = 1; i < record.size(); i++) {
        Writable edge = record.get(i);
        System.out.println(edge.toString());
        if (!( edge.equals(NullWritable.get()))) {
          vertex.addEdge(new Text(edge.toString()), NullWritable.get());
        }
      }
      LOG.info("vertex edgs size: "
          + (vertex.hasEdges() ? vertex.getEdges().size() : 0));
      context.addVertexRequest(vertex);
    }

  }

  private static void printUsage() {
    System.out.println("Usage: <in> <out> [Max iterations (default 30)]");
    System.exit(-1);
  }

  public static void main(String[] args) throws IOException {
    if (args.length < 2)
      printUsage();

    GraphJob job = new GraphJob();

    job.setGraphLoaderClass(PageRankVertexReader.class);
    job.setVertexClass(PageRankVertex.class);
    job.addInput(TableInfo.builder().tableName(args[0]).build());
    job.addOutput(TableInfo.builder().tableName(args[1]).build());

    // Default max iteration is 30; override with a third argument.
    job.setMaxIteration(30);
    if (args.length >= 3)
      job.setMaxIteration(Integer.parseInt(args[2]));

    long startTime = System.currentTimeMillis();
    job.run();
    System.out.println("Job Finished in "
        + (System.currentTimeMillis() - startTime) / 1000.0 + " seconds");
  }
}

Próximos passos