Ошибка кодека "ascii" не может декодировать байт 0xc3 в позиции 149: порядковый номер не в диапазоне (128)'при восстановлении индекса стога сена

У меня есть приложение, в котором я должен хранить имена людей и делать их доступными для поиска. Технологии, которые я использую, - это python (v2.7.6) django (v1.9.5). DBMS является postgresql (v9.2). Поскольку имена пользователей могут быть арабскими, мы используем utf-8 в качестве кодировки db. Для поиска мы используем стог сена (v2.4.1) с Amazon Elastic Search для индексации. Индекс строился нормально несколько дней назад, но теперь, когда я пытаюсь восстановить его с

python manage.py rebuild_index

это терпит неудачу со следующей ошибкой

'ascii' codec can't decode byte 0xc3 in position 149: ordinal not in range(128)

Полная трассировка ошибок

  File "/usr/local/lib/python2.7/dist-packages/haystack/management/commands/update_index.py", line 188, in handle_label
    self.update_backend(label, using)
  File "/usr/local/lib/python2.7/dist-packages/haystack/management/commands/update_index.py", line 233, in update_backend
    do_update(backend, index, qs, start, end, total, verbosity=self.verbosity, commit=self.commit)
  File "/usr/local/lib/python2.7/dist-packages/haystack/management/commands/update_index.py", line 96, in do_update
    backend.update(index, current_qs, commit=commit)
  File "/usr/local/lib/python2.7/dist-packages/haystack/backends/elasticsearch_backend.py", line 193, in update
    bulk(self.conn, prepped_docs, index=self.index_name, doc_type='modelresult')
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/helpers/__init__.py", line 188, in bulk
    for ok, item in streaming_bulk(client, actions, **kwargs):
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/helpers/__init__.py", line 160, in streaming_bulk
    for result in _process_bulk_chunk(client, bulk_actions, raise_on_exception, raise_on_error, **kwargs):
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/helpers/__init__.py", line 85, in _process_bulk_chunk
    resp = client.bulk('\n'.join(bulk_actions) + '\n', **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/client/utils.py", line 69, in _wrapped
    return func(*args, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/client/__init__.py", line 795, in bulk
    doc_type, '_bulk'), params=params, body=self._bulk_body(body))
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/transport.py", line 329, in perform_request
    status, headers, data = connection.perform_request(method, url, params, body, ignore=ignore, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/elasticsearch/connection/http_requests.py", line 68, in perform_request
    response = self.session.request(method, url, data=body, timeout=timeout or self.timeout)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 455, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 558, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 330, in send
    timeout=timeout
  File "/usr/local/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 558, in urlopen
    body=body, headers=headers)
  File "/usr/local/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 353, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib/python2.7/httplib.py", line 979, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.7/httplib.py", line 1013, in _send_request
    self.endheaders(body)
  File "/usr/lib/python2.7/httplib.py", line 975, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python2.7/httplib.py", line 833, in _send_output
    msg += message_body
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 149: ordinal not in range(128)

Я предполагаю, что раньше у нас не было арабских символов в нашей базе данных, поэтому индекс строился нормально, но теперь, когда пользователи вводят арабские символы, индекс не может быть создан.

3 ответа

Если вы используете пакет запросы-aws4auth, вы можете использовать следующий класс-оболочку вместо AWS4Auth учебный класс. Он кодирует заголовки, созданные AWS4Auth в байтовые строки, таким образом избегая UnicodeDecodeError вниз по течению.

from requests_aws4auth import AWS4Auth

class AWS4AuthEncodingFix(AWS4Auth):
    def __call__(self, request):
        request = super(AWS4AuthEncodingFix, self).__call__(request)

        for header_name in request.headers:
            self._encode_header_to_utf8(request, header_name)

        return request

    def _encode_header_to_utf8(self, request, header_name):
        value = request.headers[header_name]

        if isinstance(value, unicode):
            value = value.encode('utf-8')

        if isinstance(header_name, unicode):
            del request.headers[header_name]
            header_name = header_name.encode('utf-8')

        request.headers[header_name] = value

Elasticsearch поддерживает различные кодировки, поэтому наличие арабских символов не должно быть проблемой.

Поскольку вы используете AWS, я предполагаю, что вы также используете некоторую библиотеку авторизации, например, request-aws4auth. В этом случае обратите внимание, что во время авторизации добавляются некоторые заголовки Unicode, например u'x-amz-date', Это проблема, так как httplib python выполняет следующее во время _send_output(): msg = "\r\n".join(self._buffer) где _buffer - список заголовков HTTP. Наличие юникодных заголовков делает msg быть одним из <type 'unicode'> в то время как это действительно должно быть типа str ( Здесь похожая проблема с другой библиотекой аутентификации).

Строка, которая вызывает исключение, msg += message_body поднимает его, так как Python должен декодировать message_body Unicode, чтобы он соответствовал типу сообщения. Возникло исключение, так как py -asticsearch уже позаботился о кодировке, поэтому мы заканчиваем кодирование в unicode дважды, что вызывает исключение (как объяснено здесь).

Вы можете попробовать заменить библиотеку auth (например, на DavidMuller / aws-запросы-auth) и посмотреть, решит ли она проблему.

Я подозреваю, что вы правы насчет арабских символов, которые теперь отображаются в БД.

также возможно связаны с этой проблемой. Первая ссылка, кажется, имеет какое-то решение для этого, но не имеет много деталей. Я подозреваю, что автор имел в виду

Правильное решение заключается в том, чтобы использовать тип Юникода вместо str или правильно установить кодировку по умолчанию (я полагаю) utf-8.

является то, что вам нужно проверить, что машина, на которой он работает LANG=en_US.UTF-8 или хотя бы какой-нибудь UTF-8 LANG

Другие вопросы по тегам