Tous les produits
Search
Centre de documentation

MaxCompute:PageRank

Dernière mise à jour :Aug 10, 2026

L'algorithme PageRank attribue un score d'importance aux sommets d'un graphe orienté. Chaque sommet représente une page web et chaque arête orientée symbolise un lien hypertexte d'une page vers une autre. Une page recevant des liens depuis d'autres pages bien notées obtient un score plus élevé. Ce principe explique pourquoi un compte Twitter suivi par des utilisateurs influents est mieux classé qu'un compte suivi par des bots.

Fonctionnement

Au début de chaque exécution, tous les sommets reçoivent le même score initial : 1 / TotalNumVertices.

À chaque superstep, chaque sommet envoie un vote à ses voisins. La valeur du vote correspond au score actuel du sommet divisé par son degré sortant :

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

À la fin de chaque superstep, chaque sommet recalcule son score en additionnant tous les votes entrants et en appliquant un facteur d'amortissement :

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

Le facteur d'amortissement (0,85) modélise la probabilité qu'un internaute naviguant au hasard suive un lien plutôt que de sauter vers une page aléatoire. Le complément (0,15) garantit que chaque sommet conserve un score de base non nul, même en l'absence de liens entrants.

Par défaut, l'algorithme s'exécute jusqu'à 30 itérations (ce paramètre est configurable).

Prérequis

Avant de commencer, assurez-vous d'avoir :

Exécuter l'exemple PageRank

Étape 1 : Préparer le fichier JAR

Placez le fichier graph-examples.jar dans le dossier data\resources situé dans le répertoire bin du client MaxCompute.

Étape 2 : Créer les tables d'entrée et de sortie

Exécutez les instructions SQL suivantes dans le client MaxCompute :

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

La table pagerank_in utilise la première colonne comme sommets source et les colonnes restantes comme sommets de destination.

Étape 3 : Enregistrer le fichier JAR

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

Étape 4 : Charger les données de test

Depuis le répertoire bin du client MaxCompute, chargez le fichier data.txt dans la table pagerank_in :

tunnel upload data.txt pagerank_in;

Le fichier data.txt contient les arêtes du graphe suivantes :

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

Chaque ligne indique un sommet source suivi de ses sommets de destination. Par exemple, le sommet 1 possède des arêtes pointant vers les sommets 2 et 4.

Étape 5 : Exécuter la tâche

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

Paramètres de la tâche

Paramètre

Description

Valeur par défaut

pagerank_in

Nom de la table d'entrée

pagerank_out

Nom de la table de sortie

Nombre maximal d'itérations (troisième argument facultatif)

Nombre maximal de supersteps avant l'arrêt de la tâche

30

Pour modifier le nombre maximal d'itérations, transmettez-le en tant que troisième argument :

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

Résultats attendus

Une fois la tâche terminée, interrogez la table pagerank_out :

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

Le sommet 2 obtient le score le plus élevé car les sommets 1 et 4 pointent vers lui. De plus, le sommet 1 reçoit lui-même des liens entrants des sommets 2 et 3. Le sommet 4 affiche le score le plus bas : seul le sommet 1 pointe vers lui et aucun sommet fortement noté ne lui accorde de vote significatif.

Pour effectuer un débogage local avant de soumettre la tâche au cluster, consultez la section Débogage local .

Exemple de code

L'implémentation Java complète est présentée ci-dessous. Les classes clés sont :

  • PageRankVertex : définit la logique de calcul pour chaque sommet

  • PageRankVertexReader : charge la table d'entrée et construit le graphe

  • main : configure et exécute la tâche 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");
  }
}

Étapes suivantes