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

com.aliyun.odps.graph.VertexResolver Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 com.aliyun.odps.graph;

import java.io.IOException;

import com.aliyun.odps.conf.Configuration;
import com.aliyun.odps.io.Writable;
import com.aliyun.odps.io.WritableComparable;

/**
 * VertexResolver 用于自定义图拓扑修改时的冲突处理逻辑.
 *
 * 

* ODPS Graph 程序在图加载或迭代计算过程中可以对图拓扑结构进行修改,包括添加、删除点或者边,详见框架提供的 * {@link MutationContext} 接口说明,对图拓扑结构的修改请求可能引起下面几种类型的“冲突”: *

    *
  • 添加重复点:通常使用 {@linkplain MutationContext#addVertexRequest(Vertex) * addVertexRequest} 添加点,而相同 ID 的点已经存在。 *
  • 添加重复边:通常使用 * {@linkplain MutationContext#addEdgeRequest(WritableComparable, Edge) * addEdgeRequest} 添加边时,而相同起点和终点的边已经存在;或者使用 * {@linkplain MutationContext#addVertexRequest(Vertex) addVertexRequest} * 添加点时,待添加点中存在重复边。 *
  • 删除不存在的边:通常使用 * {@linkplain MutationContext#removeEdgeRequest(WritableComparable, WritableComparable) * removeEdgeRequest} 删除边时,待删除的边不存在。 *
  • 删除不存在的点:通常使用 * {@linkplain MutationContext#removeVertexRequest(WritableComparable) * removeVertexRequest} 删除点时,待删除的点不存在。 *
  • 发送消息到不存在的点:通常使用 * {@linkplain ComputeContext#sendMessage(WritableComparable, Writable) * sendMessage} 发送消息时,目标点不存在。 *
* 当上述冲突发生时:如果用户提供了冲突处理的实现类,框架会把同一个点相关的冲突信息封装成 {@link VertexChanges},调用用户自定义类的 * {@linkplain #resolve(WritableComparable, Vertex, VertexChanges, boolean) * resolve} 方法进行处理;如果没有提供冲突处理的实现类,框架默认会抛异常。 *

{@link GraphJob} 提供两个方法设置冲突处理的实现类: *
    *
  • {@linkplain JobConf#setLoadingVertexResolverClass(Class) * setLoadingVertexResolverClass} 设置图加载时的冲突处理实现类,框架提供一个默认实现 * {@link DefaultLoadingVertexResolver} *
  • {@linkplain JobConf#setComputingVertexResolverClass(Class) * setComputingVertexResolverClass} * ,设置迭代计算过程中的冲突处理实现类,框架未提供默认实现,如果发生图拓扑结构修改请求,框架直接抛异常。 *
* * @param * Vertex ID 类型 * @param * Vertex Value 类型 * @param * Edge Value 类型 * @param * Message 类型 * @see MutationContext * @see JobConf#setLoadingVertexResolverClass(Class) * @see JobConf#setComputingVertexResolverClass(Class) * @see DefaultLoadingVertexResolver */ @SuppressWarnings("rawtypes") public abstract class VertexResolver { /** * 此方法在对象被创建后立即调用,用户可以覆盖(override)本方法进行对象的初始化. * * @param conf * 运行时的JobConf对象 */ public void configure(Configuration conf) throws IOException { } /** * 冲突处理方法,用户需要实现此方法自定义冲突处理逻辑. * *

* 在图载入和迭代计算过程中,用户可以调用 {@link MutationContext} * 接口对图进行修改,例如增加、删除点或者边,框架会将这些图拓扑变动请求按相关的点 (这里“相关的点”指待增加/删除点的 ID,待增加/删除边的起始点的 * ID)进行归类,封装成 {@link VertexChanges} 对象,用户可以实现本方法对这些相关的图拓扑变动请求进行冲突处理。 *

* *

* 实现时,建议参考 {@link DefaultLoadingVertexResolver} 的源代码,见在线文档。 *

* *

* 注意:基于性能上的考虑,框架直接使用本方法返回的 {@link Vertex} 对象,用户应保证本方法返回的 * {@link Vertex} 对象及其成员变量在内部不被复用,否则会导致逻辑错误。 *

* * 正确的实现(保证返回值不被复用): * *
   * public Vertex resolve(I vertexId, Vertex vertex,
   *    VertexChanges vertexChanges, boolean hasMessages) throws IOException {
   *    List> vertices = vertexChanges.getAddedVertexList();
   *    if (vertices.size() > 0) {
   *      // vertexChanges中的对象可以直接使用,无需拷贝
   *      return vertices.get(0);
   *    } else {
   *      // 每次重新创建一个Vertex对象,保证返回值不被重用
   *      MyVertex vertex = new MyVertex();
   *      // vertexId可以直接使用,无需拷贝
   *      vertex.setId(vertexId);
   *      List> edges = vertexChanges.getAddedEdgeList();
   *      for (Edge> edge: edges) {
   *        // Vertex对象中填充的内容,来自VertexChanges的无需拷贝
   *        vertex.addEdge(edge.getDestVertexId(), edge.getValue());
   *      }
   *      return vertex;
   *    }
   * }
   * 
* * 错误的实现: * *
   * MyVertex vertex = new MyVertex();
   * public Vertex resolve(I vertexId, Vertex vertex,
   *    VertexChanges vertexChanges, boolean hasMessages) throws IOException {
   *    List> edges = vertexChanges.getAddedEdgeList();
   *    for (Edge> edge: edges) {
   *      vertex.addEdge(edge.getDestVertexId(), edge.getValue());
   *    }
   *    // vertex不断被复用,导致最后参与计算的Vertex只有最后一个返回的Vertex
   *    return vertex;
   * }
   * 
* * @param vertexId * 待解决冲突的点 ID,总不为 null * @param vertex * 与 vertexId 对应的原 {@link Vertex} 对象,如果对应点不存在,此参数为 null,对于图载入阶段,此参数总为 * null * @param vertexChanges * 与 vertexId 相关的图拓扑变动请求 * @param hasMessages * 上一轮迭代是否发送消息到此点,对于图载入阶段,此参数总为 false * @return 返回的 {@link Vertex} 对象,如果不为 null,则添加到图中; 如果为 null,但输入的原始 vertex不为 * null,则从图中删除原始点,应保证该对象及其成员变量不被复用 */ public abstract Vertex resolve(I vertexId, Vertex vertex, VertexChanges vertexChanges, boolean hasMessages) throws IOException; }