当前位置: 首页 > 面试题库 >

在neo4j的bulbs框架中是否有等同的提交

欧阳俊晖
2023-03-14
问题内容

我正在构建一个基于neo4j的数据密集型Python应用程序,出于性能原因,我需要在每个事务期间创建/恢复多个节点和关系。session.commit()灯泡中是否有等效的SQLAlchemy语句?

编辑:

对于那些感兴趣的人,已经开发了与Bulbs的接口,该接口实现了本机功能,而其他功能几乎类似于SQLAlchemy:https
:
//github.com/chefjerome/graphalchemy


问题答案:

执行多部分事务的最有效方法是将事务封装在Gremlin脚本中,然后将其作为单个请求执行。

这是一个示例,它是我去年为Neo4j Heroku Challenge开发的一个示例应用程序。

该项目被称为灯泡:https://github.com/espeed/lightbulb

自述文件描述了它的作用…

什么是灯泡?

Lightbulb是一个用Python编写的,用于Heroku的,由Git驱动,受Neo4j支持的博客引​​擎。

您可以在Emacs(或您喜欢的文本编辑器)中编写博客条目,并使用Gi​​t进行版本控制,而无需放弃动态应用程序的功能。

用ReStructuredText编写博客条目,然后使用您网站的模板系统设置样式。

当您按下Heroku时,条目元数据将自动保存到Neo4j,并且将从ReStructuredText源文件生成的HTML片段从磁盘提供。

但是,Neo4j放弃了在免费/测试版的Heroku Add On上提供Gremlin的功能,因此Lightbulb将不适用于新Neo4j /
Heroku用户。

明年-在TinkerPop书问世之前-
TinkerPop将发布具有Gremlin全面支持的Rexster Heroku Add On,以便人们在阅读书的过程中可以在Heroku上运行项目。

但就目前而言,您无需担心应用程序的运行-所有相关代码都包含在这两个文件中-Lightbulb应用程序的模型文件及其Gremlin脚本文件:

https://github.com/espeed/lightbulb/blob/master/lightbulb/model.py

https://github.com/espeed/lightbulb/blob/master/lightbulb/gremlin.groovy

model.py提供了用于构建自定义Bulbs模型和自定义BulbsGraph类的示例。

gremlin.groovy包含自定义Entry模型执行的自定义Gremlin脚本-
此Gremlin脚本封装了整个多部分事务,以便可以将其作为单个请求执行。

注意,在model.py上面的文件中,我EntryProxy通过覆盖create()update()方法进行自定义,而是定义一个单一的save()方法来处理创建和更新。

要将自定义添加EntryProxyEntry模型中,我只需重写Entry模型的get_proxy_class方法,以便它返回EntryProxy类而不是默认NodeProxy类。

Entry模型中的所有其他内容都是围绕为save_blog_entryGremlin脚本(在上面的gremlin.groovy文件中定义)构建数据而设计的。

注意在gremlin.groovy中,该save_blog_entry()方法很长,并且包含多个闭包。您可以将每个闭包定义为一个独立的方法,并通过多个Python调用执行它们,但是这样做会产生多个服务器请求的开销,并且由于请求是分开的,因此无法将它们全部包装在事务中。

通过使用单个Gremlin脚本,您可以将所有内容组合到单个事务请求中。这要快得多,而且是事务性的。

您可以在Gremlin方法的最后一行中看到如何执行整个脚本:

return transaction(save_blog_entry);

在这里,我只是将事务闭包包装在内部save_blog_entry闭包中的所有命令周围。进行事务关闭可以使代码保持隔离状态,并且比将事务逻辑嵌入到其他关闭中要干净得多。

然后,如果您查看内部save_blog_entry闭包中的代码,它只是使用我在Entry模型中调用脚本时从Python传入的参数来调用我上面定义的其他闭包:

def _save(self, _data, kwds):
    script = self._client.scripts.get('save_blog_entry')
    params = self._get_params(_data, kwds)
    result = self._client.gremlin(script, params).one()

我传入的参数是在模型的自定义_get_parms()方法中建立的:

def _get_params(self, _data, kwds):
    params = dict()

    # Get the property data, regardless of how it was entered
    data = build_data(_data, kwds)

    # Author
    author = data.pop('author')
    params['author_id'] = cache.get("username:%s" % author)

    # Topic Tags
    tags = (tag.strip() for tag in data.pop('tags').split(','))
    topic_bundles = []
    for topic_name in tags:
        #slug = slugify(topic_name)
        bundle = Topic(self._client).get_bundle(name=topic_name)
        topic_bundles.append(bundle)
    params['topic_bundles'] = topic_bundles


    # Entry
    # clean off any extra kwds that aren't defined as an Entry Property
    desired_keys = self.get_property_keys()
    data = extract(desired_keys, data)
    params['entry_bundle'] = self.get_bundle(data)

    return params

_get_params()是在做什么…

buld_data(_data, kwds)是在bulbs.element以下位置定义的函数:https
:
//github.com/espeed/bulbs/blob/master/bulbs/element.py#L959

万一用户输入了一些作为位置args和一些作为关键字args的情况,它只是合并了args。

在第一个参数我传递到_get_params()author,这是笔者的用户名,但我不通过用户名到小鬼剧本,我通过了author_id。将author_id被缓存,所以我使用的用户名来查找author_id,并设置为PARAM,我稍后会传递给小鬼save_blog_entry脚本。

然后,我Topic
Model为设置的每个Blog标签创建对象,然后调用get_bundle()每个对象并将其另存为topic_bundlesin paras列表。

get_bundle()方法在bulbs.model中定义:https
:
//github.com/espeed/bulbs/blob/master/bulbs/model.py#L363

它只是返回一个包含一个元组dataindex_name和指数keys的模型实例:

def get_bundle(self, _data=None, **kwds):
    """
    Returns a tuple containing the property data, index name, and index keys.

    :param _data: Data that was passed in via a dict.
    :type _data: dict

    :param kwds: Data that was passed in via name/value pairs.
    :type kwds: dict

    :rtype: tuple

    """
    self._set_property_defaults()   
    self._set_keyword_attributes(_data, kwds)
    data = self._get_property_data()
    index_name = self.get_index_name(self._client.config)
    keys = self.get_index_keys()
    return data, index_name, keys

我将get_bundle()方法添加到Bulbs中,以提供一种很好的,整洁的将参数捆绑在一起的方法,因此您的Gremlin脚本不会因其签名中的大量参数而被溢出。

最后,对于Entry,我只需创建一个entry_bundle并将其存储为参数。

请注意,_get_params()返回dict三个PARAMS:
author_idtopic_bundleentry_bundle

params dict直接传递给Gremlin脚本:

def _save(self, _data, kwds):
    script = self._client.scripts.get('save_blog_entry')
    params = self._get_params(_data, kwds)
    result = self._client.gremlin(script, params).one()        
    self._initialize(result)

Gremlin脚本的arg名称与传递的arg名称相同params

def save_blog_entry(entry_bundle, author_id, topic_bundles) {

   // Gremlin code omitted for brevity

}

然后根据需要在Gremlin脚本中简单地使用这些参数-没什么特别的。

因此,既然我已经创建了自定义模型和Gremlin脚本,我将构建一个自定义Graph对象,该对象封装了所有代理和相应的模型:

class Graph(Neo4jGraph):

    def __init__(self, config=None):
        super(Graph, self).__init__(config)

        # Node Proxies
        self.people = self.build_proxy(Person)
        self.entries = self.build_proxy(Entry)
        self.topics = self.build_proxy(Topic)

        # Relationship Proxies
        self.tagged = self.build_proxy(Tagged)
        self.author = self.build_proxy(Author)

        # Add our custom Gremlin-Groovy scripts
        scripts_file = get_file_path(__file__, "gremlin.groovy")
        self.scripts.update(scripts_file)

现在,您可以Graph直接从应用程序中导入,model.py并像平常一样实例化该Graph对象。

>> from lightbulb.model import Graph  
>> g = Graph()
>> data = dict(username='espeed',tags=['gremlin','bulbs'],docid='42',title="Test")
>> g.entries.save(data)         # execute transaction via Gremlin script

有帮助吗?



 类似资料:
  • 问题内容: 我有一个byte [],想将其复制到另一个byte []中。也许我在这里展示了我的简单“ C”背景,但是在Java字节数组中是否有等同于memcpy()的东西? 问题答案: 您可以尝试或使用阵列功能,在像类。两者都应在引擎盖下为您提供本机性能。 Arrays.copyOf可能对可读性有利,但仅在Java 1.6中引入。

  • 请注意,我使用以下代码得到了相同的结果: 所以问题是,fooObservable直到订阅了PublishSubject之后才订阅PublishSubject, 是否有一种方法可以在第一次订阅FooObservable之后立即运行代码? 如果请求与已经订阅的请求匹配,那么observable应该在订阅时立即提供最新的匹配值。 当没有订阅者时,我需要取消我包装的服务的订阅。

  • 问题内容: 如果我想分配一个char数组(用C表示),该数组保证足够大以容纳任何有效的绝对路径名和文件名,那么它需要多大。 在Win32上,有MAX_PATH定义。Unix / linux相当于什么? 问题答案: 有一个,但是有点问题。从realpath(3)手册页的bug部分中: 此功能的POSIX.1-2001标准版本在设计上已被破坏,因为无法确定输出缓冲区 resolve_path 的合适大

  • 问题内容: 不幸的是,HTML中没有CDATA。 遗憾的是,因为它非常适合添加包含XML的注释,因此您不必转义<和>,例如: 但是,可以识别CDATA部分,然后将其转换为HTML。例如: 或者它可以使用比CDATA更简单的语法。因为是可扩展的,所以可能有人添加了此功能。也许已经将它埋在里面的某处…有人知道吗? 问题答案: 您可以使用JavaDoc的标签:

  • 就像Java 8中的(在某种程度上)与Scala的类型等价一样,是否存在与Scala的等价的类型?

  • 我只是在练习msdn中的代码第一个新数据库实体框架,我想知道是否可以在代码第一个新数据库EF中创建没有主键的表?