【问题标题】:Elasticsearch Python emojis and term offsets in analyzers分析器中的 Elasticsearch Python 表情符号和术语偏移
【发布时间】:2015-09-19 07:30:40
【问题描述】:

我在 Python 客户端中使用 Elasticsearch,我对 unicode、ES、分析器和表情符号之间的交互有疑问。当我尝试通过 ES 分析器运行包含表情符号字符的 unicode 文本字符串时,它似乎搞砸了结果输出中的术语偏移量。

例如:

>> es.indices.analyze(body=u'\U0001f64f testing')
{u'tokens': [{u'end_offset': 10,
   u'position': 1,
   u'start_offset': 3,
   u'token': u'testing',
   u'type': u'<ALPHANUM>'}]}

这给了我术语测试的错误偏移量。

>> u'\U0001f64f testing'[3:10]
u'esting'

如果我使用另一个 unicode 外来字符(例如日元符号),我不会得到同样的错误。

>> es.indices.analyze(body=u'\u00A5 testing')
{u'tokens': [{u'end_offset': 9,
   u'position': 1,
   u'start_offset': 2,
   u'token': u'testing',
   u'type': u'<ALPHANUM>'}]}

>> u'\u00A5 testing'[2:9]
u'testing'

谁能解释一下是怎么回事?

【问题讨论】:

    标签: python unicode elasticsearch emoji elasticsearch-py


    【解决方案1】:

    我遇到了完全相同的问题,并通过在UTF-16 中来回编码来正确映射偏移量:

    TEXT = "? carrot"
    TOKENS = es.indices.analyze(body=TEXT)["tokens"]
    # [
    #   {
    #     "token" : """?""",
    #     "start_offset" : 0,
    #     "end_offset" : 2,
    #     "type" : "<EMOJI>",
    #     "position" : 0
    #   },
    #   {
    #     "token" : "carrot",
    #     "start_offset" : 3,
    #     "end_offset" : 9,
    #     "type" : "<ALPHANUM>",
    #     "position" : 1
    #   }
    # ]
    
    ENCODED_TEXT = text.encode("utf-16")
    # b'\xff\xfe>\xd8U\xdd \x00c\x00a\x00r\x00r\x00o\x00t\x00'
    BOM_MARK_OFFSET = 2
    
    def get_decoded_token(encoded_text, token):
        start_offset = (token["start_offset"] * 2) + BOM_MARK_OFFSET
        end_offset = (token["end_offset"] * 2) + BOM_MARK_OFFSET
        return encoded_text[start_offset:end_offset].decode("utf-16")
    
    assert get_decoded_token(ENCODED_TEXT, TOKENS[0]) == "?"
    assert get_decoded_token(ENCODED_TEXT, TOKENS[1]) == "carrot"
    
    

    对于BOM_OFFSET_MARK,请参阅https://en.wikipedia.org/wiki/Byte_order_mark#UTF-16

    【讨论】:

      【解决方案2】:

      Python 3.2 或更早版本?在 Windows 上的 Python 3.3 之前,有窄和宽的 Unicode 版本。窄版本每个字符使用两个字节,并使用 UTF-16 对 Unicode 代码点进行内部编码,这需要两个 UTF-16 代理来编码高于 U+FFFF 的 Unicode 代码点。

      Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:35:05) [MSC v.1600 64 bit (AMD64)] on win32
      Type "help", "copyright", "credits" or "license" for more information.
      >>> len('\U0001f64f')
      1
      >>> '\U0001f64f'[0]
      '\U0001f64f'
      
      Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
      Type "help", "copyright", "credits" or "license" for more information.
      >>> len(u'\U0001f64f')
      2
      >>> u'\U0001f64f'[0]
      u'\ud83d'
      >>> u'\U0001f64f'[1]
      u'\ude4f'
      

      但是,在您的情况下,偏移量是正确的。因为 U+1F64F 使用了两个 UTF-16 代理,“t”的偏移量是 3。我不确定你是怎么得到你的输出的:

      Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
      Type "help", "copyright", "credits" or "license" for more information.
      >>> x=u'\U0001f64f testing'
      >>> x
      u'\U0001f64f testing'
      >>> x[3:10]
      u'testing'
      >>> y = u'\u00a5 testing'
      >>> y[2:9]
      u'testing'
      

      【讨论】:

      • 在 Python 2 上,有窄(你的情况,Windows)和宽 CPython 构建,例如,在 Ubuntu 上 u'\U0001f64f'[0] == u'\U0001f64f'
      猜你喜欢
      • 2015-06-07
      • 1970-01-01
      • 2020-07-19
      • 2011-06-15
      • 2016-12-31
      • 2013-03-22
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多