Java uniqueKey生成在SolrCloud中不起作用(但在独立的情况下起作用)

Java uniqueKey生成在SolrCloud中不起作用(但在独立的情况下起作用),java,apache,solr,Java,Apache,Solr,我遇到了一个奇怪的问题,当同一个应用程序代码在SolrCloud中索引一个没有唯一键(应该由SOLR自动生成)的文档时失败,并在独立的SOLR实例中成功索引它(或者甚至在云模式下,但从其中一个副本的web界面)。很明显,区别只存在于客户端(CloudSolrClient vs HttpSolrClient)和SOLR URL(Zokeeper主机名+端口vs独立SOLR实例主机名和端口)之间 我正在使用Solr5.1。在云模式下,我有1个碎片和3个副本。 : 架构默认值和copyFields不能

我遇到了一个奇怪的问题,当同一个应用程序代码在SolrCloud中索引一个没有唯一键(应该由SOLR自动生成)的文档时失败,并在独立的SOLR实例中成功索引它(或者甚至在云模式下,但从其中一个副本的web界面)。很明显,区别只存在于客户端(CloudSolrClient vs HttpSolrClient)和SOLR URL(Zokeeper主机名+端口vs独立SOLR实例主机名和端口)之间

我正在使用Solr5.1。在云模式下,我有1个碎片和3个副本。 :

架构默认值和copyFields不能用于填充uniqueKey字段。您可以使用UUIDUpdateProcessorFactory自动生成uniqueKey值

因此,我已将我的uniqueKey字段添加到架构中:

<fieldType name="uuid" class="solr.UUIDField" indexed="true" />
...
<field name="id" type="uuid" indexed="true" stored="true" required="true" />
...
<uniqueKey>id</uniqueKey>
  • 在SOLR cloud模式下,当从一个副本的web界面添加文档时,更新请求是(通过检查web界面发出的调用发现):

  • 在这两种情况下,有效载荷类似于:

    {
        "add": {
            "doc": {
                     .....
            },
            "boost": 1.0,
            "overwrite": true,
            "commitWithin": 1000
        }
    }
    
    如果使用CloudSolrClient,会发生以下情况(通过调试发现):

  • 使用ZK和一些逻辑,构建了副本的URL列表,如下所示:

    [http://replica_1_host:port/solr/collection_name/,
     http://replica_2_host:port/solr/collection_name/,
     http://replica_3_host:port/solr/collection_name/]
    
  • 此代码称为:

    LBHttpSolrClient.Req req = new LBHttpSolrClient.Req(request, theUrlList);
    LBHttpSolrClient.Rsp rsp = lbClient.request(req);
    return rsp.getResponse();
    
    其中第二行出现异常而失败

  • 如果要进一步调试第二行,它将调用HttpClient.execute(从HttpSolrClient.executeMethod)来执行以下操作:

    第一个请求返回400个错误请求,副本1记录在日志中“Document is missing mandatory uniqueKey field:id”

    有趣的是,当我使用POSTMAN(但是使用JSON而不是二进制负载)执行相同的请求时,它就可以工作了!我做错什么了吗?我想这肯定是在请求的方式上

    更新:


    我使用本地代理来查看我的应用程序发送的这两个请求之间的差异,以便了解它们之间的差异。看起来唯一的区别是内容类型。在云模式下,发布文档的有效负载以“application/javabin”的形式发送,而在独立模式下,它以“application/xml;charset=UTF-8”的形式发送。其他一切都一样。第一个请求的结果是400,而第二个请求的结果是200。我认为这可能是一个SolrJ/SOLR错误,因此提交了一份文件。将保持此线程的更新。

    首先,它在独立模式下工作,因为版本5.1中的HttpSolrClient以XML形式发送负载(不包括空值-这一部分很重要),而CloudSolrClient以二进制序列化格式(包括空值)以“application/javabin”的形式发送负载。在6.2版中,这两个版本都以二进制序列化格式将有效负载发送为“application/javabin”,因此在6.2版中,云模式和独立模式都会出现此问题

    问题的真正原因是为了生成UUID,字段必须完全不存在。如果它存在且为空,则跳过UUID生成。这就是错误的原因。所以,如果我们使用SolrInputDocument对文档进行索引,那么这很容易——我们不应该为“id”字段添加值。但是如果我们使用带有“org.apache.solr.client.solrj.beans.Field”注释的POJO呢?我们不能从中排除字段。这就是发挥作用的地方:

    <updateRequestProcessorChain name="uuid">
        <!-- Using IgnoreFieldUpdateProcessorFactory because of https://issues.apache.org/jira/browse/SOLR-9493:
             can't generate UUID for a field coming as NULL, field must be absent. -->
        <processor class="solr.IgnoreFieldUpdateProcessorFactory">
            <str name="fieldName">id</str>
        </processor>
        <processor class="solr.UUIDUpdateProcessorFactory">
            <str name="fieldName">id</str>
        </processor>
        <processor class="solr.RunUpdateProcessorFactory" />
    </updateRequestProcessorChain>
    
    
    身份证件
    身份证件
    

    将其保存在solrconfig.xml中,并使用“uuid”updateRequestProcessorChain(如上面的问题所示),一切都像一个符咒一样工作(“id”字段在生成uuid之前从文档中删除)。虽然在这种情况下无法添加带有自定义ID的文档,但这是另一个线程的问题。

    可能是配置没有传播到所有节点吗?那么,当您在云模式下运行时,接收文档的服务器没有定义更新链?另外,在运行时-例如日志/分发/更新步骤。不,我已经检查过了。所有节点的配置都是完美的。另外,我可以看到对同一个节点的请求失败,即第一个副本。如果请求是从web或非云SolrClient发送的,则该节点可以完美地处理该请求。
    {
        "add": {
            "doc": {
                     .....
            },
            "boost": 1.0,
            "overwrite": true,
            "commitWithin": 1000
        }
    }
    
    [http://replica_1_host:port/solr/collection_name/,
     http://replica_2_host:port/solr/collection_name/,
     http://replica_3_host:port/solr/collection_name/]
    
    LBHttpSolrClient.Req req = new LBHttpSolrClient.Req(request, theUrlList);
    LBHttpSolrClient.Rsp rsp = lbClient.request(req);
    return rsp.getResponse();
    
    POST http://replica_1_host:port/solr/collection_name/update?wt=javabin&version=2 HTTP/1.1
    POST http://replica_2_host:port/solr/collection_name/update?wt=javabin&version=2 HTTP/1.1
    POST http://replica_3_host:port/solr/collection_name/update?wt=javabin&version=2 HTTP/1.1
    
    <updateRequestProcessorChain name="uuid">
        <!-- Using IgnoreFieldUpdateProcessorFactory because of https://issues.apache.org/jira/browse/SOLR-9493:
             can't generate UUID for a field coming as NULL, field must be absent. -->
        <processor class="solr.IgnoreFieldUpdateProcessorFactory">
            <str name="fieldName">id</str>
        </processor>
        <processor class="solr.UUIDUpdateProcessorFactory">
            <str name="fieldName">id</str>
        </processor>
        <processor class="solr.RunUpdateProcessorFactory" />
    </updateRequestProcessorChain>