Asynchronous OrientDB异步执行脚本并以惰性方式获取记录

Asynchronous OrientDB异步执行脚本并以惰性方式获取记录,asynchronous,lazy-loading,orientdb,orientdb2.2,Asynchronous,Lazy Loading,Orientdb,Orientdb2.2,目前,我们正在OrientDB 2.2版中使用文档API。假设我们有一个阶级公司和一个阶级雇员。假设我们对所有公司感兴趣,其中至少有一名员工的名字来自任意列表。在我们的公司架构中,员工被定义为LinkedList。 我们的查询看起来像这样: select from Company where employees in (select from Employee where name in ["John", "Paul"]) select from Company let $e = select

目前,我们正在OrientDB 2.2版中使用文档API。假设我们有一个阶级公司和一个阶级雇员。假设我们对所有公司感兴趣,其中至少有一名员工的名字来自任意列表。在我们的公司架构中,员工被定义为LinkedList。 我们的查询看起来像这样:

select from Company where employees in (select from Employee where name in ["John", "Paul"])
select from Company let $e = select from employees where name in ["John", "Paul"] where employees in $e
目前我们定义了以下两个索引:

Company.employees(员工链接上的索引(其@rid))->字典哈希索引和 Employee.name->notunique索引

使用explain执行上述查询时,我们看到只使用了第二个索引Employee.name,因为我们没有将上述索引定义为复合索引。据我所知,Orient 2.x不支持跨不同类的复合索引,比如我们的例子。 类似这样的查询:

select from Company where employees in (select from Employee where name in ["John", "Paul"])
select from Company let $e = select from employees where name in ["John", "Paul"] where employees in $e
也不要解决我们的问题

在不同的博客上搜索发现了两条建议:

  • 尝试通过继承定义复合索引,方法是在employee和company上引入父类,并在该父类上定义上述两个索引
  • 将两个查询捆绑在一个批处理纸条中,如下所示:
  • String cmd=“begin\n”; cmd+=“让a=从员工中选择姓名”+query+“\n”; cmd+=“让b=从员工所在的公司中选择$a\n”; cmd+=“提交\n”; cmd+=“返回$b”

    建议1对我们不起作用

    建议2。工作。在每个单独的查询中都使用了这两个索引,但随后我们遇到了Orient的下一个限制。批处理脚本似乎只能同步执行,这意味着我们只能一次以列表的形式获取结果,而不能以惰性的方式逐个获取结果,在我们的例子中,这是由于内存开销而无法实现的

    我们尝试的一个简单解决方法如下:

    public class OCommandAsyncScript extends OCommandScript implements OCommandRequestAsynch{
      public OCommandAsyncScript(String sql, String cmd) {
        super(sql, cmd);
      }
    
      @Override
      public boolean isAsynchronous() {
        return true;
      }
    
      private void containsAtLeastOne(final @Nonnull ODatabaseDocumentTx documentTx,
                                      final @Nonnull Consumer<Company> matchConsumer,
                                      final @Nonnull String queryText
                                      ) throws TimeoutException {
    
        String cmd = "begin\n";
        cmd += "let a = select from Employee where name " + queryText + "\n";
        cmd += "let b = select from Company where employees in $a\n";
        cmd += "COMMIT\n";
        cmd += "return $b";
        final OCommandHandler resultListener = new OCommandHandler(documentTx, (document -> {
          final Company companies = document2model(document);
          matchConsumer.accept(company);
        }));
    
        OCommandAsyncScript request =  new OCommandAsyncScript("sql", cmd);
        request.setResultListener(resultListener);
        documentTx.command(request).execute();
        ...
      }
    }
    
    
    public class OCommandHandler implements OCommandResultListener {
      private final ODatabaseDocumentTx database;
      private final Consumer<ODocument> matchConsumer;
    
      public OCommandHandler(
          final @Nonnull ODatabaseDocumentTx database,
          final @Nonnull Consumer<ODocument> matchConsumer
        ) {
        this.database = database;
        this.matchConsumer = matchConsumer;
      }
    
      @Override
      public boolean result(Object iRecord) {
        if (iRecord != null) {
    
          final ODocument document = (ODocument) iRecord;
    
          /*
          Result handler might be asynchronous, if document is loaded in a lazy mode,
          database will be queries to fetch various fields. Need to activate it on the current thread.
          */
          database.activateOnCurrentThread();
          matchConsumer.accept(document);
        }
        return true;
      }
      ...
    }
    
    公共类OCommandAsyncScript扩展了OCommandScript实现了OCommandRequestAsynch{
    公共OCommandAsyncScript(字符串sql、字符串cmd){
    super(sql,cmd);
    }
    @凌驾
    公共布尔同步(){
    返回true;
    }
    私有void containsAtLeastOne(最终@Nonnull ODatabaseDocumentTx documentTx,
    最终@Nonnull Consumer matchConsumer,
    final@Nonnull字符串queryText
    )抛出TimeoutException{
    String cmd=“begin\n”;
    cmd+=“让a=从名为“+queryText+”\n”的员工中选择;
    cmd+=“让b=从员工所在的公司中选择$a\n”;
    cmd+=“提交\n”;
    cmd+=“返回$b”;
    最终OCommandHandler resultListener=新的OCommandHandler(documentTx,(文档->{
    最终公司=文件2模型(文件);
    匹配消费者。接受(公司);
    }));
    OCommandAsyncScript请求=新的OCommandAsyncScript(“sql”,cmd);
    setResultListener(resultListener);
    documentTx.command(request.execute();
    ...
    }
    }
    公共类OCommandHandler实现OCommandResultListener{
    专用最终ODatabaseDocumentTx数据库;
    私人最终消费者;
    公共命令处理程序(
    最终@Nonnull ODatabaseDocumentTx数据库,
    最终@Nonnull使用者匹配使用者
    ) {
    this.database=数据库;
    this.matchConsumer=matchConsumer;
    }
    @凌驾
    公共布尔结果(对象iRecord){
    如果(iRecord!=null){
    最终气味文件=(气味文件)i记录;
    /*
    如果文档以惰性模式加载,则结果处理程序可能是异步的,
    数据库将被查询以获取各种字段。需要在当前线程上激活它。
    */
    database.activateOnCurrentThread();
    matchConsumer.accept(文档);
    }
    返回true;
    }
    ...
    }
    
    不幸的是,定义自定义OCommandAsyncScript的方法不起作用。调试Orient的OStorageRemote类时,似乎无法读取部分结果,以下是源代码的相应摘录:

    public Object command(final OCommandRequestText iCommand) {
    ....
    
    try {
      OStorageRemote.this.beginResponse(network, session);
      List<ORecord> temporaryResults = new ArrayList();
      boolean addNextRecord = true;
      byte status;
      if(asynch) {
        while((status = network.readByte()) > 0) {
          ORecord record = (ORecord)OChannelBinaryProtocol.readIdentifiable(network);
          if(record != null) {
            switch(status) {
              case 1:
                if(addNextRecord) {
                  addNextRecord = iCommand.getResultListener().result(record);
                  database.getLocalCache().updateRecord(record);
                }
                break;
            case 2:
              if(record.getIdentity().getClusterId() == -2) {
                  temporaryResults.add(record);
                }
              database.getLocalCache().updateRecord(record);
            }
          }
        }
      }
    }
    
    公共对象命令(最终OCommandRequestText iCommand){
    ....
    试一试{
    OStorageRemote.this.beginResponse(网络、会话);
    List temporaryResults=新建ArrayList();
    布尔addNextRecord=true;
    字节状态;
    如果(异步){
    而((status=network.readByte())>0){
    ORecord记录=(ORecord)OChannelBinaryProtocol.readIdentification(网络);
    if(记录!=null){
    开关(状态){
    案例1:
    如果(添加下一条记录){
    addNextRecord=iCommand.getResultListener().result(记录);
    database.getLocalCache().updateRecord(记录);
    }
    打破
    案例2:
    if(record.getIdentity().getClusterId()=-2){
    临时结果。添加(记录);
    }
    database.getLocalCache().updateRecord(记录);
    }
    }
    }
    }
    }
    
    Network.readbyte()始终为空,因此无法提取任何记录

    还有其他解决方法吗?我们如何在异步模式下执行sql脚本,并以惰性方式检索结果,以防止在应用程序端生成大型列表