2016-09-11 3 views
1

Я хотел бы вывести результаты StanfordNLP в protobuf (поскольку его размер намного меньше) и прочитать результаты на python. Как мне это сделать?Прочитайте Protobuf Сериализация вывода StanfordNLP в Python

Я следовал инструкции here для вывода результатов сериализовать ProtobufAnnotationSerializer, как это:

java -cp "stanford-corenlp-full-2015-12-09/*" \ 
edu.stanford.nlp.pipeline.StanfordCoreNLP \ 
-annotators tokenize,ssplit \ 
-file input.txt \ 
-outputFormat serialized \ 
-outputSerializer \ 
edu.stanford.nlp.pipeline.ProtobufAnnotationSerializer 

Затем использовать protoc скомпилировать CoreNLP.proto, который поставляется вместе с исходным кодом StanfordNLP, в Python модулей, как это:

protoc --python_out=. CoreNLP.proto 

Затем в питона прочитать файлы обратно, как это:

import CoreNLP_pb2 
doc = CoreNLP_pb2.Document() 
doc.ParseFromString(open('input.txt.ser.gz', 'rb').read()) 

Разбор выдает следующее сообщение об ошибке

--------------------------------------------------------------------------- 
DecodeError        Traceback (most recent call last) 
<ipython-input-213-d8eaeb9c2048> in <module>() 
     1 doc = CoreNLP_pb2.Document() 
----> 2 doc.ParseFromString(open('imed/s5_tokenized/conv-00000.ser.gz', 'rb').read()) 

/usr/local/lib/python2.7/dist-packages/google/protobuf/message.pyc in ParseFromString(self, serialized) 
    183  """ 
    184  self.Clear() 
--> 185  self.MergeFromString(serialized) 
    186 
    187 def SerializeToString(self): 

/usr/local/lib/python2.7/dist-packages/google/protobuf/internal/python_message.pyc in MergeFromString(self, serialized) 
    1092   # The only reason _InternalParse would return early is if it 
    1093   # encountered an end-group tag. 
-> 1094   raise message_mod.DecodeError('Unexpected end-group tag.') 
    1095  except (IndexError, TypeError): 
    1096  # Now ord(buf[p:p+1]) == ord('') gets TypeError. 

DecodeError: Unexpected end-group tag. 

UPDATE:

Я спросил автор сериализатора Габор Анджел и получил ответ. Объекты protobuf были записаны в файлы с writeDelimitedTo в this line. Изменение его на writeTo сделало бы выходные файлы доступными для чтения в Python.

+0

Какую версию протока вы используете? 'protoc --version' – sberry

+0

@sberry: выводится« libprotoc 3.0.0 ». – shaoyl85

+0

Это также может быть проблемой (не знаю, какая версия была использована для создания .java-файлов), но сначала увидим мой ответ, потому что это тоже проблема. – sberry

ответ

2

Этот вопрос, похоже, появился снова, поэтому я решил, что напишу правильный ответ. Корень проблемы заключается в том, что proto написан с использованием метода Java writeDelimitedTo, который Google не реализовал для Python. Обходной будет использовать следующий метод, чтобы прочитать файл прото (предполагается, что файл не являющийся файл - вы можете заменить f.read() с соответствующим кодом, чтобы распаковать файл в зависимости от обстоятельств):

from google.protobuf.internal.decoder import _DecodeVarint 
import CoreNLP_pb2 

def readCoreNLPProtoFile(protoFile): 
    protos = [] 
    with open(protoFile, 'rb') as f: 
    # -- Read the file -- 
    data = f.read() 
    # -- Parse the file -- 
    # In Java. there's a parseDelimitedFrom() method that makes this easier 
    pos = 0 
    while (pos < len(data)): 
     # (read the proto) 
     (size, pos) = _DecodeVarint(data, pos) 
     proto = CoreNLP_pb2.Document() 
     proto.ParseFromString(data[pos:(pos+size)]) 
     pos += size 
     # (add the proto to the list; or, `yield proto`) 
     protos.append(proto) 
    return protos 

Файл CoreNLP_pb2 является составленный из файла CoreNLP.proto в репо с командой:

protoc --python_out /path/to/output/ /path/to/CoreNLP.proto 

Обратите внимание, что в написании этой версии (3.7.0) формат proto2, не proto3.