alibaba / havenask

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

utf8编码字节数大于3的字符无法召回

breeent opened this issue · comments

用以下数据建库

CMD=add^_
id=1^_
query=𣄃的组词^_
^^
CMD=add^_
id=2^_
query=形容北京城^_
^^
CMD=add^_
id=3^_
query=怎么读𠀋这个字^_
^^

用“𣄃“,”𠀋“无法召回原文档。查看代码发现是Analyzer的normalize()函数内部会调用

int32_t EncodeConverter::utf8ToUtf16(const char *in, int32_t length, uint16_t *out) {
    int32_t ret = 0;
    const unsigned char *b = reinterpret_cast<const unsigned char *>(in);
    const unsigned char *e = b + length;
    bool error = false;
    while (b < e) {
        if (*b < 128) {
            out[ret++] = *b++;
        } else if ((*b & 0xE0) == 0xC0) {
            uint16_t u = ((*b++) & (0x1F));
            if (b < e && (*b & 0xC0) == 0x80) {
                out[ret++] = (u << 6) | ((*b++) & 0x3F);
            } else {
                error = true;
            }
        } else if ((*b & 0xF0) == 0xE0) {
            uint16_t u = ((*b++) & (0xF));
            if (b < e && (*b & 0xC0) == 0x80) {
                u = (u << 6) | ((*b++) & 0x3F);
                if (b < e && (*b & 0xC0) == 0x80) {
                    out[ret++] = (u << 6) | ((*b++) & 0x3F);
                } else {
                    error = true;
                }
            } else {
                error = true;
            }
        } else {
            error = true;
            b++;
        }
    }

    if (error) {
        AUTIL_LOG(DEBUG, "invalid utf8 [%s]", std::string(in, length).c_str());
    }
    return ret;
}

这个函数并没有处理utf8字符为四字节的情况,而且在后续的NormalizeTable中也只分配了0x10000个uint16_t的空间,因此只能处理Unicode码小于0x10000的字符。

如果文档包含Unicode码大于0x10000(utf8编码字节数大于3)的字符,需要把analyzer.json里面的normalize_options都设置为true,让代码不走normalize逻辑,但是大小写、全半角、繁简体的转换就得预先处理了。

            "normalize_options" :
            {
                "case_sensitive" : false,
                "traditional_sensitive" : true,
                "width_sensitive" : false
            }

这个有fix的方案吗?

我们先确认下

确实存在这个问题,只支持对常用的文字做normalize,fix的方案还要好好梳理下,你这边只能先关闭normalize选项,在外部normalize。我们先记录这个问题,再下一个版本尝试修复

或者你是否可以修复一下,我们merge进来,主要的代码逻辑在autil/autil/codec/下面