如何以递归方式遍历java中的graphql文档并找到它达到的最深层次

时间:2017-08-22 23:30:26

标签: java recursion graphql graphql-java

我的目标是遍历graphql Java文档对象并返回最大深度。

示例:深度0

{
   name 
}

示例:深度1

{
   viewer{
     viewerId
   }
}

示例:深度2

{
   viewer{
     albums{
       albumId
     }
   }
}

示例:深度2.正如您所看到的,两张专辑/歌曲都位于相同的父级'查看器

{
   viewer{
     albums{
       albumId
     }
     songs{
        songId
     }
   }
}

示例:深度3

{
   viewer{
     albums{
       tracks{
          trackId
       }
     }
   }
}

我已经编写了基本代码来遍历它但我的代码不适用于深度= 2的第二个版本。它返回深度= 3而不是2.原因是因为它计算了两次同一个父母。基本上逻辑是这样的:每当一个领域有孩子时,深度=深度+ 1。

import graphql.language.Document;
import graphql.language.Node;
import graphql.language.OperationDefinition;

public int checkDepthLimit(String query) {
    Document document;
    try {
        document = documentParser.parseDocument(query);
    } catch (Exception e) {}

    Optional<Node> queryNode = document.getChildren().stream()
            .filter(n -> (n.getClass() == OperationDefinition.class))
            .findFirst();

    return checkDepthLimit(queryNode.get());

}
private int checkDepthLimit(Node queryNode) {

    int depth = 0;
    String nodeType = queryNode.getClass().getSimpleName().toUpperCase();

    if (nodeType.equals("FIELD")) {
        if (!queryNode.getChildren().isEmpty()) {
            depth += 1;
        }
    }

    List<Node> nodeChildren = queryNode.getChildren();
    for (int i = 0; i < nodeChildren.size(); i++) {
        depth += checkDepthLimit(nodeChildren.get(i));
    }
    return depth;

}
String query = "{
       viewer{
           viewerId
       }"
QueryComplexity c = new QueryComplexity();
int depth = c.checkDepthLimit(query);

如果有更深入了解递归知识的人能够帮助我,我会感到困惑并非常感激。

2 个答案:

答案 0 :(得分:3)

错误是您迭代孩子的地方。正如您已经认识到的那样(“计算两次”),您将每个孩子的深度添加到当前深度,但您应该只添加最深的一个。

这就是诀窍:

request_log

答案 1 :(得分:2)

从graphql-java v4.0开始,有一个内置的QueryTraversal类可以帮助您检查查询AST和用于限制深度的相关工具:MaxQueryDepthInstrumentation

只需像其他任何仪器一样注册它:

public static class PetService {

    @GraphQLQuery(name = "pet")
    @GraphQLComplexity("type == 'big' ? 2 : 10") //JavaScript expression calculating the complexity
    public Pet findPet(@GraphQLArgument(name = "type") String type) {
        return db.findPetByType(type);
    }
}

还有MaxQueryComplexityInstrumentation

graphql-spqr(由我编写)还以声明方式指定字段复杂性:

ComplexityAnalysisInstrumentation

您手动注册GraphQL runtime = GraphQL.newGraphQL(schema) .instrumentation(new ComplexityAnalysisInstrumentation(new JavaScriptEvaluator(), MAX_DEPTH)) .build(); ,与上面相同:

GraphQLRuntime

或使用SPQR的GraphQL runtime = GraphQLRuntime.newGraphQL(schema) .maximumQueryComplexity(maxComplexity) .build(); 包装器:

import org.apache.spark.sql.functions.spark_partition_id

df.groupBy(spark_partition_id).count