Rexster + Bulbs:Unicode节点属性 - 已创建但未找到的节点

时间:2014-04-14 10:36:02

标签: unicode bulbs rexster

我正在使用bulbsrexster,并尝试使用unicode属性存储节点(请参阅下面的示例)。 显然,在图表中创建节点可以正常工作,因为我可以看到rexster(Rexster Dog House)附带的Web界面中的节点但是检索相同的节点不起作用 - 我得到的只是None

当我创建并查找属性中包含非unicode特定字母的节点时,一切都按预期工作。 例如。在以下示例中,可以按预期检索具有name = u'University of Cambridge'的节点。

Rexster版本:

[INFO] Application - Rexster version [2.4.0]

示例代码:

# -*- coding: utf-8 -*-


from bulbs.rexster import Graph
from bulbs.model import Node
from bulbs.property import String
from bulbs.config import DEBUG
import bulbs

class University(Node):
    element_type = 'university'
    name = String(nullable=False, indexed=True)


g = Graph()
g.add_proxy('university', University)
g.config.set_logger(DEBUG)

name = u'Université de Montréal'

g.university.create(name=name)

print g.university.index.lookup(name=name)

print bulbs.__version__

在命令行上提供以下输出:

POST url: http://localhost:8182/graphs/emptygraph/tp/gremlin
POST body: {"params": {"keys": null, "index_name": "university", "data": {"element_type": "university", "name": "Universit\u00e9 de Montr\u00e9al"}}, "script": "def createIndexedVertex = {\n vertex = g.addVertex()\n index = g.idx(index_name)\n for (entry in data.entrySet()) {\n if (entry.value == null) continue;\n vertex.setProperty(entry.key,entry.value)\n if (keys == null || keys.contains(entry.key))\n\tindex.put(entry.key,String.valueOf(entry.value),vertex)\n }\n return vertex\n }\n def transaction = { final Closure closure ->\n try {\n results = closure();\n g.commit();\n return results; \n } catch (e) {\n g.rollback();\n throw e;\n }\n }\n return transaction(createIndexedVertex);"} GET url: http://localhost:8182/graphs/emptygraph/indices/university?value=Universit%C3%A9+de+Montr%C3%A9al&key=name
GET body: None None 0.3

1 个答案:

答案 0 :(得分:2)

好的,我终于明白了。

由于TinkerGraph使用HashMap作为索引,因此您可以通过使用Gremlin返回地图内容来查看索引中存储的内容。

以上使用您的灯泡g.university.create(name=name)方法存储在TinkerGraph索引中的内容......

$ curl http://localhost:8182/graphs/emptygraph/tp/gremlin?script="g.idx(\"university\").index"
{"results":[{"name":{"Université de Montréal":[{"name":"Université de Montréal","element_type":"university","_id":"0","_type":"vertex"}]},"element_type":{"university":[{"name":"Université de Montréal","element_type":"university","_id":"0","_type":"vertex"}]}}],"success":true,"version":"2.5.0-SNAPSHOT","queryTime":3.732632}

所有看起来都很好 - 编码看起来正确。

要像上面那样创建和索引顶点,Bulbs通过带有JSON内容类型的HTTP POST请求使用自定义Gremlin脚本。

这就是问题......

Rexster的索引查找REST端点使用URL查询参数,Bulbs将URL参数编码为UTF-8字节字符串。

要了解Rexster如何处理编码为UTF-8字节字符串的URL查询参数,我通过URL查询参数执行了Gremlin脚本,该参数只返回编码的字符串......

$ curl http://localhost:8182/graphs/emptygraph/tp/gremlin?script="'Universit%C3%A9%20de%20Montr%C3%A9al'"
{"results":["Université de Montréal"],"success":true,"version":"2.5.0-SNAPSHOT","queryTime":16.59432}

扯扯!那不对。如您所见,该文本被破坏了。

具有讽刺意味的是,我们让Gremlin回归小鬼,这就是Rexster在索引查找中使用的关键值,正如我们所看到的那样,这不是什么' s存储在TinkerGraph的HashMap索引中。

这里发生了什么......

这是未加引号的字节字符串在Bulbs中的样子:

>>> name
u'Universit\xe9 de Montr\xe9al'

>>> bulbs.utils.to_bytes(name)
'Universit\xc3\xa9 de Montr\xc3\xa9al'

'\xc3\xa9'是unicode字符u'\xe9'的UTF-8编码(也可以指定为u'\u00e9')。

UTF-8使用2个字节对​​字符进行编码,而Jersey / Grizzly 1.x(Rexster的应用服务器)有一个错误,它不能正确处理像UTF-这样的双字节字符编码8。

请参阅http://markmail.org/message/w6ipdpkpmyghdx2p

看起来这在Jersey / Grizzly 2.0中得到了修复,但将Rexster从Jersey / Grizzly 1.x切换到Jersey / Grizzly 2.x是一个很大的考验。

去年TinkerPop决定转而使用Netty,因此对于今年夏天发布的TinkerPop 3,Rexster正在变身为Gremlin Server,它基于Netty而不是Grizzly。

在此之前,这里有一些解决方法......

由于Grizzly无法处理像UTF-8这样的2字节编码,因此客户端库需要将URL参数编码为1字节latin1编码(AKA ISO-8859-1),这是Grizzly的默认编码编码

这里的相同值编码为latin1字节字符串...

 $ curl http://localhost:8182/graphs/emptygraph/tp/gremlin?script="'Universit%E9%20de%20Montr%E9al'"
{"results":["Université de Montréal"],"success":true,"version":"2.5.0-SNAPSHOT","queryTime":17.765313}

如您所见,在这种情况下使用latin1编码。

但是,出于一般目的,客户端库可能最好通过具有JSON内容类型的HTTP POST请求使用自定义Gremlin脚本,从而避免URL param编码问题 - 这就是灯泡将要做,我今天晚些时候将灯泡更新推送到GitHub。

UPDATE :事实证明,即使我们无法更改Grizzly的默认编码类型,我们也可以将HTTPF-8指定为HTTP请求Content-Type标头中的字符集,灰熊会用它。灯泡0.3.29已更新为在其请求标头中包含UTF-8字符集,并且所有测试都通过。该更新已被推送到GitHub和PyPi。