2017-04-19 59 views
2

我有表稱爲Message的請求,其具有類型JSONSQLAlchemy的JSON字段內的文本匹配數據以UTF-8

我的模型定義的列的內容是如下

class Message(db.Model): 
    ... 
    content = db.Column(JSON) 
    ... 

現在我執行文本匹配與下面的查詢

Message.query.filter(Message.content['summary'].cast(Unicode).match(term)) 

它工作得很好,直到長期簡單的搜索有一個UTF-8字符,如德國變音符號或法國口音。

這裏的解決方案是什麼?

也記住我使用Python 3

+0

你需要'cast'方法嗎?解析必須在解析JSON之前執行*,因此當您訪問content ['summary']'時,應該已經發生了。 – lenz

+0

@lenz可能是的,否則如果我刪除它,我得到這個錯誤sqlalchemy.exc.ProgrammingError:(psycopg2.ProgrammingError)運算符不存在:json @@ tsquery 線3:WHERE bots_messages.content - >'summary'@ @ to_tsquery(bla bla bla – EzzatA

+0

)你應該在問題中包括'Message'的定義,因爲它是手頭問題的關鍵部分(json vs. jsonb)。 –

回答

3

問題出在一個PostgreSQL jsoncast(Unicode)。在Postgresql VARCHAR的情況下,它簡單地將json映射到底層SQLAlchemy的文本類型Unicode。換句話說,它會生成JSON的字符串表示形式,而不是提取文本內容。如果您的輸入包含轉義的unicode代碼點,則在這種情況下它們將按原樣輸出。給定一個簡單的模型Testjson數據

In [7]: t = Test(data={'summary': 'Tämä on summary.'}) 

In [8]: session.add(t) 

In [9]: session.commit() 

In [11]: session.query(Test.data['summary'].cast(Unicode)).scalar() 
Out[11]: '"T\\u00e4m\\u00e4 on summary."' 

它應該是顯而易見的,爲什麼用轉義Unicode字符匹配將失敗。提取文本內容的正確方式,進行反向轉義逃跑的unicode,就是用astext,它使用PostgreSQL中->> operator

In [13]: session.query(Test.data['summary'].astext).scalar() 
Out[13]: 'Tämä on summary.' 

引述JSON的函數和操作文檔:

Note: Many of these functions and operators will convert Unicode escapes in JSON strings to the appropriate single character. This is a non-issue if the input is type jsonb, because the conversion was already done; but for json input, this may result in throwing an error, as noted in Section 8.14 .

因此,在您案例:

Message.query.\ 
    filter(Message.content['summary'].astext.match(term)) 

請注意,這僅適用於json類型,而不是jsonb,因爲json類型不會在輸入上轉換unicode轉義。另一方面,jsonbconverts all unicode escapes to equivalent ASCII or UTF-8 characters for storage。如果我們的Test模型包含在第二列data2 jsonb,具有完全相同的輸入,那麼結果將是:

In [11]: session.query(Test.data['summary'].cast(Unicode), 
    ...:    Test.data2['summary'].cast(Unicode)).first() 
Out[11]: ('"T\\u00e4m\\u00e4 on summary."', '"Tämä on summary"') 

不過,你應該使用astext,如果你想文本而不是JSON的字符串表示。

+0

非常感謝非常豐富和有益的答案:) – EzzatA

+0

不客氣。最初的解釋是缺乏和有點錯誤,所以更新提到'json'和'jsonb'和unicode轉義之間的區別。 –