JAVA细节使用20131129

1.

首先还是先放出本例中的查询语句:

PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>
PREFIX  rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX  people: <http://org.semwebprogramming/chapter2/people#>

SELECT DISTINCT  ?name
WHERE
  { people:me foaf:name ?name }

前几天一直在寻找的最终处理类应该就是AlgebraGenerator这个类,这个类的解释是“ Class used to compile SPARQL queries into SPARQL algebra”,也即是说将sparql查询语句编译成sparql代数。这个类中有许多的编译方法,我们使用的编译方法是protected Op compileModifiers(Query query, Op pattern),这个方法的具体内容如下:

    protected Op compileModifiers(Query query, Op pattern)
    {
         /* The modifier order in algebra is:
          * 
          * Limit/Offset
          *   Distinct/reduce
          *     project
          *       OrderBy
          *         Bindings
          *           having
          *             select expressions
          *               group
          */
        
        // Preparation: sort SELECT clause into assignments and projects.
        VarExprList projectVars = query.getProject() ;
        
        VarExprList exprs = new VarExprList() ;     // Assignments to be done.
        List<Var> vars = new ArrayList<Var>() ;     // projection variables
        
        Op op = pattern ;
        
        // ---- GROUP BY
        
        if ( query.hasGroupBy() )
        {
            // When there is no GroupBy but there are some aggregates, it's a group of no variables.
            op = new OpGroup(op, query.getGroupBy(), query.getAggregators()) ;
        }
        
        //---- Assignments from SELECT and other places (so available to ORDER and HAVING)
        // Now do assignments from expressions 
        // Must be after "group by" has introduced it's variables.
        
        // Look for assignments in SELECT expressions.
        if ( ! projectVars.isEmpty() && ! query.isQueryResultStar())
        {
            // Don't project for QueryResultStar so initial bindings show
            // through in SELECT *
            if ( projectVars.size() == 0 && query.isSelectType() )
                Log.warn(this,"No project variables") ;
            // Separate assignments and variable projection.
            for ( Var v : query.getProject().getVars() )
            {
                Expr e = query.getProject().getExpr(v) ;
                if ( e != null )
                {
                    Expr e2 = ExprLib.replaceAggregateByVariable(e) ;
                    exprs.add(v, e2) ;
                }
                // Include in project
                vars.add(v) ;
            }
        }
        
        // ---- Assignments from SELECT and other places (so available to ORDER and HAVING)
        if ( ! exprs.isEmpty() )
            // Potential rewrites based of assign introducing aliases.
            op = OpExtend.extend(op, exprs) ;

        // ---- HAVING
        if ( query.hasHaving() )
        {
            for (Expr expr : query.getHavingExprs())
            {
                // HAVING expression to refer to the aggregate via the variable.
                Expr expr2 = ExprLib.replaceAggregateByVariable(expr) ; 
                op = OpFilter.filter(expr2 , op) ;
            }
        }
        // ---- VALUES
        if ( query.hasValues() )
        {
            Table table = TableFactory.create(query.getValuesVariables()) ;
            for ( Binding binding : query.getValuesData() )
                table.addBinding(binding) ;
            OpTable opTable = OpTable.create(table) ;
            op = OpJoin.create(op, opTable) ;
        }
        
        // ---- ToList
        if ( context.isTrue(ARQ.generateToList) )
            // Listify it.
            op = new OpList(op) ;
        
        // ---- ORDER BY
        if ( query.getOrderBy() != null )
        {
            List<SortCondition> scList = new ArrayList<SortCondition>() ;

            // Aggregates in ORDER BY
            for ( SortCondition sc : query.getOrderBy() )
            {
                Expr e = sc.getExpression() ;
                e = ExprLib.replaceAggregateByVariable(e) ;
                scList.add(new SortCondition(e, sc.getDirection())) ;
                
            }
            op = new OpOrder(op, scList) ;
        }
        
        // ---- PROJECT
        // No projection => initial variables are exposed.
        // Needed for CONSTRUCT and initial bindings + SELECT *
        
        if ( vars.size() > 0 )
            op = new OpProject(op, vars) ;
        
        // ---- DISTINCT
        if ( query.isDistinct() )
            op = OpDistinct.create(op) ;
        
        // ---- REDUCED
        if ( query.isReduced() )
            op = OpReduced.create(op) ;
        
        // ---- LIMIT/OFFSET
        if ( query.hasLimit() || query.hasOffset() )
            op = new OpSlice(op, query.getOffset() /*start*/, query.getLimit()/*length*/) ;
        
        return op ;
    }

由方法里的注释可以看到modifier其实就是sparql中的功能关键字,前面一直在搞的是将sparql中的查询WHERE中的模式进行各种变换,但始终没有涉及对其功能性关键字的处理,而这里就是对其的处理。

来分析这个函数的处理过程:

VarExprList projectVars = query.getProject() ;

这里是将query中的查询值数组放在VarExprList类中,在本例中,查询值只有一个?name。

下面是:

        VarExprList exprs = new VarExprList() ;     // Assignments to be done.
        List<Var> vars = new ArrayList<Var>() ;     // projection variables
        Op op = pattern ;

这两句话创造了两个计算中需要用到的中间量,以及一个用来承载传入pattern的变量op。

下面就是一堆对query中之前手贱创造的标记位的判断了:

if ( query.hasGroupBy() )
if ( ! projectVars.isEmpty() && ! query.isQueryResultStar())
if ( ! exprs.isEmpty() )
if ( query.hasHaving() )
if ( query.hasValues() )
if ( context.isTrue(ARQ.generateToList) )
if ( query.getOrderBy() != null )
if ( vars.size() > 0 )
if ( query.isDistinct() )
if ( query.isReduced() )
if ( query.hasLimit() || query.hasOffset() )

这一坨判断,我只打算分析本例中判断成功的,其它的,就让它自生自灭吧。

首先第一个进入的判断是:

        if ( ! projectVars.isEmpty() && ! query.isQueryResultStar())
        {
            // Don't project for QueryResultStar so initial bindings show
            // through in SELECT *
            if ( projectVars.size() == 0 && query.isSelectType() )
                Log.warn(this,"No project variables") ;
            // Separate assignments and variable projection.
            for ( Var v : query.getProject().getVars() )
            {
                Expr e = query.getProject().getExpr(v) ;
                if ( e != null )
                {
                    Expr e2 = ExprLib.replaceAggregateByVariable(e) ;
                    exprs.add(v, e2) ;
                }
                // Include in project
                vars.add(v) ;
            }
        }

这个判断很强势,首先判断有没有查询返回值,本例中,幸运地存在一个?name,然后查询query.queryResultStar这一标记为是不是为false,幸运的是,本例中枪,因此进入处理。接着使用下面这个语句一个个地取出需要的返回值。

  for ( Var v : query.getProject().getVars() )
本例中,这里只取出了一个返回值?name。因为返回值只有一个,所以下面的

               Expr e = query.getProject().getExpr(v) ;
这句其实就取到null值传给e了。这种最简单的情况下甚至连复杂一点的变换都不需要,直接将?name加入函数一开始时声明的vars值就行。至此,这个判断结束。


然后下面的判断略过一大堆,进入这个判断:

if ( vars.size() > 0 )
判断下语句就只有一个:

op = new OpProject(op, vars) ;
就是将pattern和返回的?name绑定到一起,实际跟踪后显示的就是new了一个op1类,然后将其的这两个值载入。


下一个进入的判断是:

if ( query.isDistinct() )
这个判断的执行语句也只有一个:

op = OpDistinct.create(op) ;
这个依然是new了一个继承op1的OpDistinct类然后赋给op,实际上,这两次为op赋值虽然都使用new方法创建了某种东西,但是看op的实际值就可以看到,这种两次创建并不是覆盖性的,而是顺序性的,不妨观察一下op值得变化,最早刚生成的时候,op的值为:

(bgp (triple <http://org.semwebprogramming/chapter2/people#me> <http://xmlns.com/foaf/0.1/name> ?name))
之后判断vars的size的实现语句之后,op的值为:

(project (?name)
  (bgp (triple <http://org.semwebprogramming/chapter2/people#me> <http://xmlns.com/foaf/0.1/name> ?name)))
到现在对distinct的判断之后,op的值为:

(distinct
  (project (?name)
    (bgp (triple <http://org.semwebprogramming/chapter2/people#me> <http://xmlns.com/foaf/0.1/name> ?name))))
可见每次都是对op的表述进行了某种程度的扩展。

这个判断之后,op值修改完毕,将最后的那个op值返回。


2.这里要开始涉及Plan的操作了。

Plan是个重头戏,因为最后的一些值是从Plan中取出的,因此这个东西值得好好分析:

    protected Plan createPlan()
    {
        // Decide the algebra to actually execute.
        Op op = queryOp ;
        if ( ! startBinding.isEmpty() ) {
            op = Substitute.substitute(op, startBinding) ;
            context.put(ARQConstants.sysCurrentAlgebra, op) ;
            // Don't reset the startBinding because it also is
            // needed in the output.
        }
        op = modifyOp(op) ;

        QueryIterator queryIterator = null ;
        if ( dataset != null )
            // Null means setting up but not executing a query.
            queryIterator = evaluate(op, dataset, startBinding, context) ;
        else
            // Bypass management interface
            queryIterator = evaluateNoMgt(op, dataset, startBinding, context) ;
        // This could be an automagic iterator to catch close.
        return new PlanOp(getOp(), this, queryIterator) ;
    }
首先,现将之前的Op查询语句传进来。

然后判断是否已经开始绑定,官方的解释是“Don't reset the startBinding because it also is needed in the output.”就是说不要重新进行绑定,因为这在输出的时候还需要用到,具体啥意思我没搞懂,先往下看。接着是对op进行修饰,具体的修饰是判断一些标记位然后进行一些优化,这个过程也比较长,因此先略过,本例中,这一优化后op并没有发生什么大的改变。

然后判断dataset是否为空,官方对此也有解释“Null means setting up but not executing a query.”就是说如果dataset是空就意味着dataset已经建立起来了,只是没有执行查询语句,和上面一样,官方的解释我还是不懂,官方能不能多说几句?感觉自己智商乏力。还是往下看吧,下一句的深一层执行代码是:

    // Record the query operation as it goes pass and call the actual worker
    @Override
    final
    public QueryIterator evaluate(Op op, DatasetGraph dsg, Binding binding, Context context)
    {
        if ( query != null ) 
            Explain.explain("QUERY", query, context) ;
Explain.explain("ALGEBRA", op, context) ; queryEngineInfo.incQueryCount() ; queryEngineInfo.setLastQueryExecAt() ; //queryEngineInfo.setLastQueryExecTime(-1) ; queryEngineInfo.setLastQueryString((Query)context.get(ARQConstants.sysCurrentQuery)) ; queryEngineInfo.setLastOp(op) ; return eval(op, dsg, binding, context) ; }


官方的解释是:“Record the query operation as it goes pass and call the actual worker”就是说记录查询操作当函数调用实际的处理单元的时候。

        if ( query != null ) 
            Explain.explain("QUERY", query, context) ;
这两句是用来判断当查询存在的时候,这个查询是不是已经正在执行,如果是,看起来Jena想调用一些多线程机制来定义新的查询?不知道对不对,先把猜测不负责任地放这里好了,继续往下解读,下一句和这一句的意思是一样的,只是把query换成了op。

然后几句是设置queryEngineInfo的信息。后面return了一个QueryIterator类型的东西,这个东西里面的资料很奇怪,我一开始理解的是查询结果,可又不是,又是个变种的中间变量:

QueryIterRoot
QueryIterBlockTriples
  <http://org.semwebprogramming/chapter2/people#me> <http://xmlns.com/foaf/0.1/name> ?name .
QueryIterProject ?name
QueryIterDistinct
到现在为止,我已经对变种的sparql查询见怪不怪了,这一变种被提交到上一层之后交进PlanOp函数处理:

return new PlanOp(getOp(), this, queryIterator) ;
这个过程原本以为很高端,其实就是再包装一层,其实提交上去的plan内容是:

(Plan
  QueryIteratorCloseable/QueryIteratorCheck
    QueryIterRoot
    QueryIterBlockTriples
      <http://org.semwebprogramming/chapter2/people#me> <http://xmlns.com/foaf/0.1/name> ?name .
    QueryIterProject ?name
    QueryIterDistinct
  )
plan至此已经生成完毕。

































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值