CoreNLP 使用ProtobufAnnotationSerializer时出现无效输出

eufgjt7s  于 2个月前  发布在  其他
关注(0)|答案(2)|浏览(42)

我正在运行CoreNLP服务器,并向其发送了以下请求:
wget --post-data 'the quick brown fox jumped over the lazy dog' http://localhost:9000/?properties=%7B%22annotators%22%3A%22tokenize%2Cssplit%22%2C%22outputFormat%22%3A%22serialized%22%2C%22serializer%22%3A%22edu.stanford.nlp.pipeline.ProtobufAnnotationSerializer%22%7D -O /tmp/output.bin
输出为455字节,乍一看似乎是正确的:

$ xxd /tmp/output.bin 
00000000: c503 0a2c 7468 6520 7175 6963 6b20 6272  ...,the quick br
00000010: 6f77 6e20 666f 7820 6a75 6d70 6564 206f  own fox jumped o
00000020: 7665 7220 7468 6520 6c61 7a79 2064 6f67  ver the lazy dog
00000030: 128b 030a 240a 0374 6865 1a03 7468 652a  ....$..the..the*
00000040: 0032 0120 3a03 7468 6558 0060 0388 0100  .2. :.theX.`....
00000050: 9001 01a8 0100 b002 000a 2b0a 0571 7569  ..........+..qui
00000060: 636b 1a05 7175 6963 6b2a 0120 3201 203a  ck..quick*. 2. :
00000070: 0571 7569 636b 5804 6009 8801 0190 0102  .quickX.`.......
00000080: a801 00b0 0200 0a2b 0a05 6272 6f77 6e1a  .......+..brown.
00000090: 0562 726f 776e 2a01 2032 0120 3a05 6272  .brown*. 2. :.br
000000a0: 6f77 6e58 0a60 0f88 0102 9001 03a8 0100  ownX.`..........
000000b0: b002 000a 250a 0366 6f78 1a03 666f 782a  ....%..fox..fox*
000000c0: 0120 3201 203a 0366 6f78 5810 6013 8801  . 2. :.foxX.`...
000000d0: 0390 0104 a801 00b0 0200 0a2e 0a06 6a75  ..............ju
000000e0: 6d70 6564 1a06 6a75 6d70 6564 2a01 2032  mped..jumped*. 2
000000f0: 0120 3a06 6a75 6d70 6564 5814 601a 8801  . :.jumpedX.`...
00000100: 0490 0105 a801 00b0 0200 0a28 0a04 6f76  ...........(..ov
00000110: 6572 1a04 6f76 6572 2a01 2032 0120 3a04  er..over*. 2. :.
00000120: 6f76 6572 581b 601f 8801 0590 0106 a801  overX.`.........
00000130: 00b0 0200 0a25 0a03 7468 651a 0374 6865  .....%..the..the
00000140: 2a01 2032 0120 3a03 7468 6558 2060 2388  *. 2. :.theX `#.
00000150: 0106 9001 07a8 0100 b002 000a 280a 046c  ............(..l
00000160: 617a 791a 046c 617a 792a 0120 3201 203a  azy..lazy*. 2. :
00000170: 046c 617a 7958 2460 2888 0107 9001 08a8  .lazyX$`(.......
00000180: 0100 b002 000a 240a 0364 6f67 1a03 646f  ......$..dog..do
00000190: 672a 0120 3200 3a03 646f 6758 2960 2c88  g*. 2.:.dogX)`,.
000001a0: 0108 9001 09a8 0100 b002 0010 0018 0920  ............... 
000001b0: 0028 0030 2c98 0300 b003 0088 0400 5800  .(.0,.........X.
000001c0: 6800 7800 8001 00                        h.x....

然而,我正在使用的客户端无法将此解码为Document消息。它报告错误“proto: wrong wireType = 5 for field Sections”。
所以我尝试使用protoc解析数据,结果也是错误的:

$ protoc --decode_raw < /tmp/output.bin
Failed to parse input.

似乎输出根本不是有效的protobuf数据。

q0qdq0h2

q0qdq0h21#

我认为这应该在Java代码中起作用:

// ...
import edu.stanford.nlp.io.IOUtils;
// ...
InputStream kis = IOUtils.getInputStreamFromURLOrClasspathOrFileSystem("/path/to/example.ser");
Pair<Annotation, InputStream> pair = serializer.read(kis);
pair.second.close();
Annotation readAnnotation = pair.first;

同样,在Java代码中,这个应该也行:

import edu.stanford.nlp.io.IOUtils;
import edu.stanford.nlp.simple.Document;

InputStream kis = IOUtils.getInputStreamFromURLOrClasspathOrFileSystem("/path/to/example.ser");
Document myDocument = Document.deserialize(kis);

我会尝试测试这些方法,但如果你有机会,请告诉我这两个解决方案是否可行...
如果你需要Python示例,请告诉我...

b1zrtrql

b1zrtrql2#

感谢您的回复。我尝试了您的第二个示例,它可以正常工作,所以我想弄清楚原因。Document.deserialize 使用生成的 parseDelimitedFrom 方法而不是 parseFrom。同样,Document.serialize 使用 writeDelimitedTo。"分隔"版本在每个序列化消息前放置一个 varint,这对于通过开放连接传输消息非常有用。对于 CoreNLPServer,我认为这不是必要的或可取的,因为消息长度已经在HTTP响应头中提供。

显然,Java代码生成器创建了 writeDelimitedToparseDelimitedFrom,但Golang生成器没有。现在我知道需要这样做,自己做起来也不难:

fileSize, varintSize := proto.DecodeVarint(fileData)
	t.Log(fileSize)
	t.Log(varintSize)

	var document Document
	err = proto.Unmarshal(fileData[varintSize:], &document)
	if err != nil {
		t.Fatal(err)
	}

在我上面的示例数据中,前两个字节是一个值为453的varint,剩下的453个字节是一个正确编码的 Document
documentation 表示 "edu.stanford.nlp.pipeline.ProtobufAnnotationSerializer 将输出写入协议缓冲区,如定义文件 edu.stanford.nlp.pipeline.CoreNLP.proto 中定义的。" 我认为这也应该说明它使用了分隔形式,即在 Document 消息本身之前包含一个 varint。我认为大多数人不会期望这一点。

相关问题