索引不及物和传递的n元关系。

zc.relation的Python项目详细描述


关系目录

概述

关系目录可用于优化不及物性和及物性。 搜索有限预设维度的n元关系。

例如,可以为简单的双向关系编制索引,如employee to supervisor;主谓宾语的rdf式三元组;以及更复杂的 主谓宾语与上下文和状态的关系。这些 可使用传递行为的变量定义进行搜索。

目录可以在zodb中使用,也可以单独使用。它是一个普通的,相对来说 免政策工具。

它通常被用作更专业和 受约束的工具和api。三个这样的工具是zc.relationship容器, plone.relations容器和zc.vault。包裹里的文件, 包括这个,请描述其他可能的用途。

历史记录

这是对zc.relationship包的zodb-only部分的重构。 具体来说,zc.relation目录在很大程度上等同于 关系指数。zc.relationship 2.x行中的索引是 几乎完全向后兼容的zc.relation目录包装。 ZC.关系将继续保持,尽管积极的发展 希望进入ZC.关系。

许多想法来自与凯西邓肯的讨论和代码,特雷斯 西弗、肯·曼海默等等。

设置关系目录

在本节中,我们将介绍以下想法。

  • 关系是具有索引值的对象。
  • 您可以向关系目录添加值索引,以便能够进行搜索。价值观 可以用可调用或接口元素标识到目录。这个 索引值必须作为单个值或 收藏。
  • 关系及其值作为标记存储在目录中:唯一 可以解析回原始值的标识符。整数是 最有效的代币,但其他代币也可以正常工作。
  • 令牌类型决定所需的btree模块。
  • 必须定义自己的标记化和解析标记的函数。这些 函数在关系和每个 它们的价值指数。
  • 关系用 索引 索引

我们将使用一个简单的双向关系作为例子。简介 到一个更复杂的rdf样式主谓对象可以稍后找到 在文档中。

创建目录

想象一个从一个值到另一个值的双向关系。假设我们 建立员工与上司之间的关系:员工可以 有A单一主管。在第一个例子中, 雇员和主管是内在的:雇员有一个指针指向 主管和employee对象本身表示关系。

更进一步说,为了简单起见,员工姓名是唯一的, 可用于代表员工。我们可以使用名称作为"标记"。

令牌类似于关系数据库中的主键。令牌是 识别物体的方法。它必须分类可靠,你必须能够写 在给定正确上下文的情况下可靠地解析为对象的可调用函数。在 zope 3、intid(zope.app.intid)和keyreferences(zope.app.keyreference)是 合理代币的好例子。

我们将在下面看到,您提供了一种将对象转换为令牌的方法,并 对象、关系和每个值索引的标记。 它们可以是完全相同的功能,也可以完全不同,具体取决于 您的需要。

对于速度,整数是最好的标记;其次是其他 不可变,如字符串;后跟非持久对象;后跟 持久对象。这个选择还决定了btree模块的选择,如 我们将在下面看到。

这是我们的玩具示例类。再说一次,我们将使用员工 名称作为标记。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...

因此,我们需要定义如何将员工转变为他们的代币。我们称之为 标记化一个"转储"函数。相反,将令牌解析为 对象称为"加载"。

转储关系和值的函数会得到几个参数。第一 参数是要标记化的对象。其次,因为有时候 提供上下文,就是目录。最后一个参数是 为给定搜索共享。字典可以被忽略,或者用作缓存 用于优化(例如,保存您查找的实用程序)。

在这个例子中,我们的函数很简单:我们说令牌 员工姓名。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...

如果持久地存储关系目录(例如,在zodb中),请注意 您提供的可调用函数必须是可选择的——模块级函数, 例如。

我们还需要一种方法将代币转换为员工,或"加载"。

"load"函数获取要解析的令牌;目录 上下文;和dict缓存,用于优化后续调用。

您可能已经注意到我们的 员工中有一个映射 在 employees global dict中要反对的名称的 类定义)。我们将使用它来解析令牌。

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...

现在我们知道的足够多了,可以开始目录了。我们将实例化它 通过指定如何标记关系,以及什么样的btree模块 应该用来存放代币。

你如何选择btree模块?

  • 如果令牌是32位整数,请选择 btrees.family32.ii btrees.family32.if btrees.family32.io
  • 如果令牌是64位整数,请选择 btrees.family64.ii btrees.family64.if btrees.family64.io
  • 如果它们是其他的,请选择btrees.family32.oi, btrees.family64.oi btrees.family32.oo (或 btrees.family64.oo –它们是相同的。

在这些规则中,选择有点武断,除非您计划合并 这些结果与使用特定btree的另一个源的结果相同 模块。btree set操作只能在同一个模块中工作,因此必须 将模块与模块匹配。目录默认为if树,因为 标准的zope目录使用。这是最合理的选择 如果您的令牌实际上与 zope目录,您需要执行一些设置操作。

在本例中,我们的标记是字符串,因此我们需要oo或oi变体。我们会 丘se btrees.family32.oi,任意。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)

[1]

< COL/> < COL/> <正文> < > <表>

[2]

[1]

目录提供了iCalog。

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
< COL/> < COL/> <正文> < > <表> 看!关系目录!我们做不到 不过,到目前为止,我们已经用它进行了大量的搜索,因为目录中没有 索引:

在本例中,关系本身表示雇员,因此我们不需要 单独编制索引。

但我们需要一种方法告诉目录如何找到 关系,主管。可以使用属性将其指定给目录 或从zope.interface接口指定的方法,或使用可调用的方法。 我们暂时用一个可呼叫的。可调用的将接收索引关系 以及上下文目录。

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...

我们还需要指定如何标记(转储和加载)这些值。在 在这种情况下,我们可以使用与关系本身相同的函数。 但是,请注意,我们可以指定完全不同的转储和 为每个"值索引"或关系元素加载。

我们还可以指定调用索引的名称,但它将默认为 函数(或接口元素)的 现在就给我们。

现在我们可以添加"主管"值索引。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)

现在我们有了一个索引。

[2]

zc.relationship索引的旧实例,在最新的 版本子类zc.relation catalog,用于在 内部数据结构。我们在这里指定它,以便 将dict转换为oobtree可以运行。

>>> catalog._attrs = dict(catalog._attrs)
< COL/> < COL/> <正文> < > <表>

添加关系

现在让我们创造一些员工。除了一个以外,其他人都有主管。 如果您回忆起我们的玩具employee类,则 构造函数是雇员名称(因此也是标记),并且 可选的第二个参数是主管。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
4

这是层次结构图。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
5

让我们使用 索引 方法告诉目录有关关系的信息。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
6

我们现在已经创建了关系目录并向其中添加了关系。我们准备好了 搜索!

搜索

在本节中,我们将介绍以下想法。

  • 对关系目录的查询由dict组成。
  • 查询键是要搜索的索引的名称,或者 精确关系的特例,常数
  • 查询值是要匹配的结果的标记;或者 , 指示将 none 作为值(或空集合)的关系, 如果是倍数)。搜索值可以使用 zc.relation.catalog.any(args)或 zc.relation.catalog.any(args) none)结果以匹配给定的密钥。
  • 索引有多种方法可帮助您使用标记。 tokenizequery 通常是最常用的,尽管其他可用。
  • 要查找与查询匹配的关系,请使用 findRelations findrelationtokens
  • 要查找与查询匹配的值,请使用 find values findvalues
  • 您可以使用查询工厂进行传递性搜索。这个 zc.relation.queryfactory.transportingtransitive 是一个很好的常见情况 允许您在层次结构中上下移动的工厂。查询工厂可以是 作为参数作为 queryfactory 传递给搜索方法,或 作为默认行为安装,使用 addDefaultQueryFactory
  • 要查找查询的关联方式,请使用 findRelationChains FindRelationtokenchains
  • 要确定查询是否相关,请使用 canfind
  • 循环传递关系被处理以防止无限循环。他们 在 findrelationchains findrelationtokenchains 中用 a zc.relation.interfaces.icircularrelationpath 标记接口。
  • 搜索方法共享以下参数:
    • 最大深度 ,限制搜索的传递深度;
    • 过滤,允许代码过滤可传递路径;
    • targetquery ,允许查询根据 终点的;
    • targetfilter ,允许代码根据 端点;和
    • 上述queryfactory
  • 您可以设置搜索索引以加速特定的可传递搜索。

查询、 查找关系和特殊查询值

那么谁为爱丽丝工作呢?这意味着我们想要得到关系 员工-由Alice的主管担任。

目录问题的核心是查询。拼写查询 作为字典。主要的意思是字典里的键 指定索引名称,值指定约束。

查询中的值总是用标记表示的。目录中有 好几个帮手来减轻这件事的负担,但现在让我们 我们的代币易于理解的优势。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
7

艾丽斯是贝蒂和查克的直接上司。

如果你想问"谁不向任何人报告?""那么你想 找一个没有主管的关系。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
8

爱丽丝是唯一一个不向任何人报告的雇员。

如果你想问"谁向黛安或查克报告?""然后你用 zc.relation any 类或 any 函数传递多个值。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
9

弗兰克、盖林和豪伊都向黛安娜或查克汇报。 [4]

[3]

添加值索引可以生成多个 例外情况。

您必须同时提供转储和加载,或者两者都不提供。

>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither

在这个例子中,即使我们修复了它,我们也会得到一个错误,因为我们已经 已为主管功能编制索引。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
0

您也不能在同一名称下添加其他函数。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
1

最后,如果函数没有名称 提供一个,您不能添加索引。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
2
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
3
< COL/> < COL/> <正文> < > <表>

查找值 关系 查询键

那么,我们如何找到谁是员工的主管呢?好吧,在这种情况下, 看看员工的属性!如果可以使用 通常会在ZODB中获胜。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
1

同样,正如我们在第一个例子开始时提到的,知识 对于员工实例来说,是"固有"的。它是 有可能,甚至很容易,问目录这种问题,但是 目录语法更适合于"外部"关系,例如 从主管到员工:两者之间的联系 主管对象及其员工与主管无关,因此 你可能想要一个目录来找到它!

但是,我们将非常简要地探讨语法,因为它引入了 一对重要的搜索方法,因为它是一块垫脚石 第一次传递搜索。

那么,关系目录,谁是豪伊的主管?

要问这个问题,我们需要从关系中获取索引值: 查找值 。在最简单的形式中,参数是 所需的值,以及一个查询,以查找具有所需的 值:

询问呢?上面,我们注意到查询中的键是 要搜索的索引。但是,在这种情况下,我们不想搜索 与往常一样,更多用于匹配关系的索引,但实际上指定了一个关系: Howie .

我们没有值索引名称:我们正在查找关系。查询 那么,键应该是常数zc.relation.relation 。为我们的当前 例如,这意味着查询是 {zc.relation.relation:'howie'}

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
2

恭喜,你刚刚发现 写"howie.supervisor"的方式效率低下! [5]

[4]

任何 都可以比较。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
0
< COL/> < COL/> <正文> < > <表>

[6]

[5]

这里的令牌结果是相同的。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
3

当我们在下面的脚注中,我会提到你可以 搜索尚未建立索引的关系。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
4
< COL/> < COL/> <正文> < > <表>

更有用的是,您可以使用其他查询键和 关系。这问,"贝蒂,爱丽丝,弗兰克,谁是 由爱丽丝监督?"

" < Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
6

只有贝蒂是。

代币

如上所述,目录提供了几个使用令牌的助手。 最常用的是tokenizequery,它接受一个带有对象的查询 值并使用为注册的"dump"函数将其转换为令牌 关系和索引值。以下是一些 我们在上面遇到的问题。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
7

(如果你想知道最后一个结果中的 ,是的, zc.relation.relation 只是 none 的可读性糖。

所以,这里是一个使用 tokenizequery 的实际搜索。我们将为 catalog.tokenizequery 只是为了把事情缩短一点。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
8

目录总是有并行搜索方法,一种用于查找对象的方法,如 如上所示,其中一个用于查找令牌(唯一的异常是 canfind , 如下所述)。查找标记可以更有效,特别是如果 关系目录的结果只是查找路径的一步 你想要的结果。但对于某些常见情况,查找对象更简单。 下面是上面一些查询的快速示例,获取标记而不是 对象。

您还可以使用关键字参数在 tokenizequery 中拼写查询。这个 如果您的键是 zc.relation.relation ,则不会起作用,否则它可以 提高可读性。下面我们也会看到一些例子。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
9
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
0
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
1
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
2

目录提供了其他几种仅用于处理令牌的方法。

  • resolvequery :与tokenizequaly的倒数,转换 托克尼zedquery到带有对象的查询。
  • tokenizevalues :返回给定 索引名。
  • resolveValueTokens :返回 给定索引名。
  • 标记化 :返回给定关系的标记。
  • ResolveRelationToken :返回给定令牌的关系。
  • 标记化 :返回给定关系的一个iterable标记。
  • ResolveRelationTokens :返回令牌的一个Iterable关系 给定。

这些方法使用较少,并在 这个包裹。

传递式搜索、查询工厂和最大深度

所以,我们看到了很多一级的,不及物的搜索。怎么样 传递搜索?好吧,你得告诉目录怎么走这棵树。 在这种简单(非常常见)的情况下, zc.relation.queryfactory.transportingtransitive 将起作用。

可传递查询工厂只是目录用来调用的 问"我有这个问题,这是我找到的结果。我应该 可传递地再跨出一步,那么下一步应该搜索什么查询?" 写工厂比我们现在想说的要复杂得多, 但是使用transportingtransitionvequeryfactory很容易。你只要告诉我 它应该转换两个查询名,以便在 方向。

例如,这里我们只想告诉工厂把这两个键调换一下 我们使用了, zc.relation.relation 和"supervisor"。我们建个工厂吧, 在查询中使用它进行几个可传递的搜索,然后,如果需要, 您可以通过阅读脚注来了解正在发生的事情。

这是工厂。

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
3

现在, 工厂 只是一个可调用的。让它来帮助回答几个问题 问题。

Howie所有的主管都是过渡性的(这在 图)

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
4

贝蒂所监督的人都是谁,广度优先(这个 在图表中往下看?

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
5

是的,看起来不错。那是怎么做到的?如果你在乎,读这个 脚注。 [13]

这个可传递的工厂实际上是唯一一个 需要这个特定的目录,所以连接它可能是安全的 作为违约。可以添加多个查询工厂以匹配不同的 使用 addDefaultQueryFactory进行查询

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
6

现在默认情况下,所有搜索都是可传递的。

< Buff行情>
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
7

我们可以使用 maxdepth [7]

[6]

如果您使用 findValues findValues令牌 如果试图指定一个未编入索引的值名,则会出现一个valueerror。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
5
< COL/> < COL/> <正文> < > <表>

[8]

[7]

使用a maxdepth进行搜索 不 queryfactory 引发错误。

>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
8
>>> def loadEmployees(token, catalog, cache):
...     return employees[token]
...
9
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
0
< COL/> < COL/> <正文> < > <表>

我们将介绍一些其他可用的搜索 本文档和其他文档中稍后的参数。这很重要 注意 所有搜索方法都与 ``查找关系`` findValues findValues标记 只添加 指定所需值的初始参数。

我们看了两种搜索方法目前为止的ods:find值 findRelations 方法帮助您询问相关的内容。但是如果你 想知道事物是如何传递相关的吗?

查找关联链 目标查询

另一种搜索方法,findrelationchains,可以帮助您发现 事物之间存在传递关系。

方法名为"查找关系链"。但什么是"关系" "链"?在这个api中,它是关系的传递路径。为了 例如,豪伊的指挥系统是什么? 查找关联链 将返回每个唯一路径。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
3

仔细看看结果。注意,结果是 元组。每个元组是一个唯一的链,它可能是 后继链条。在这种情况下,最后一个链是最长的 最全面。

如果我们想看看爱丽丝的路怎么办?那就是一个 为每个受监督的员工提供链,因为它显示了所有可能的路径。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
4

这就是爱丽丝的所有道路,所有的锁链。我们把结果分类, 但通常情况下,它们是宽度优先的。

但是如果我们只想找到从一个查询结果到 另一个查询结果——比如,我们想知道爱丽丝的命令链 至于豪伊?然后我们可以指定一个 targetquery 来指定 所需终点的特征。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
5

所以,贝蒂监督黛安,黛安监督豪伊。

注意 targetquery 现在将 maxdepth 加入到我们的共享集合中 搜索我们介绍的参数。

过滤器 目标过滤器

我们现在可以快速查看两个共享搜索参数中的最后一个: 过滤器 目标过滤器 。这两个相似之处在于它们都是 在基于 不管你能编什么逻辑。它们的不同之处在于 过滤器进一步停止 从关系进行传递式搜索,而 targetfilter 仅省略 给定结果,但允许进一步搜索。就像targetquery,然后, 当您想指定路径的另一端时,targetfilter 很好。

例如,假设我们只想让女性员工返回。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
6

以下是所有由Alice过渡性地监督的女性员工,使用 目标滤波器

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
7

以下是查克监督的所有女员工。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
8

作为过滤器使用的相同方法只会直接返回雌性 由其他女性监督-在这种情况下,不是Galyn。

< Buff行情>
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
9

它们可以相互结合,也可以与其他搜索相结合 参数 [9]

[8]

最大深度 必须是无或正整数,或者 否则您将得到一个值错误。

>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
1
>>> import zc.relation.catalog
>>> import BTrees
>>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
...                                       btree=BTrees.family32.OI)
2
< COL/> < COL/> <正文> 例如:

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
0 < > <表>

搜索索引

在不设置任何额外索引的情况下, findRelations 和findValues方法本质上依赖于 对 findrelationchains 的蛮力搜索。结果是难以接受的 是逐渐计算出来的。例如,让我们重复这个问题 "贝蒂监督谁?"。注意 res 首先填充一个列表 有三个成员,但不会填充第二个列表。这个 迭代器已用尽。

< Buff行情>
>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
1

在许多情况下,这种方法的强大威力是足够的,但是 有时速度为搜索搜索至关重要。在这种情况下,你可以 添加"搜索索引"。搜索索引加快了 通过索引结果进行更精确的搜索。搜索索引可以 影响 findRelations中带有 queryfactory 的搜索结果, findValues 和即将推出的 影响 findrelationchains

relation包目前包含两种搜索索引,一种是 索引可传递成员在层次结构中的搜索和一个不可传递成员的搜索 此包中tokens.rst中探索的搜索,可以优化频繁 对复杂查询的搜索或可以有效地更改 不及物搜索。其他搜索索引实现和方法可能是 以后添加。

下面是一个非常简单的例子,为transitive添加一个搜索索引 上面显示的指定"主管"的搜索。

< Buff行情>
>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
2

zc.relation.relation 描述了如何沿着链返回。搜索 在searchindex.rst中对索引进行了合理的详细说明。

现在我们已经添加了索引,我们可以再次搜索。结果是这个 时间已经计算好了,所以,至少当你要求代币时,它 可重复。

< Buff行情>
>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
3

请注意,当使用索引时,宽度优先排序将丢失 [10]

< COL/> < COL/> <正文> < > <表>

传递循环(以及更新和删除关系)

可传递搜索和提供的搜索索引可以处理 周期。在当前示例中,周期的可能性比其他一些示例小, 但我们可以把这个案子再延伸一点:想象一个"伪装的国王" 高层的人在下级工作。也许是爱丽丝 为赞恩工作,为贝蒂工作,为爱丽丝工作。人工的, 但很容易画出来:

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
7

也易于创建。

< Buff行情>
>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
8

现在我们有一个循环。当然,我们还没有告诉目录。 索引 可用于重新索引alice和index zane。

< Buff行情>
>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
9

现在,如果我们问谁为贝蒂工作,我们就得到整棵树。(我们会问 对于令牌,只需查看较小的结果即可。) [11]

[10]

我们在本文档中看到的场景显示了一个案例 其中搜索索引中的特殊逻辑需要寻址更新。 例如,如果我们将Howie从Diane移走

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
4

致Galyn

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
5

然后,新位置和旧位置的搜索索引都是正确的。

>>> from zope.interface.verify import verifyObject
>>> import zc.relation.interfaces
>>> verifyObject(zc.relation.interfaces.ICatalog, catalog)
True
6
< COL/> < COL/> <正文> < > <表>

如果我们要找弗兰克的主管,包括贝蒂。

< Buff行情>
>>> catalog._attrs = dict(catalog._attrs)
3

findRelationChains返回的路径用特殊接口标记, 以及特殊元数据,以显示链。

< Buff行情>
>>> catalog._attrs = dict(catalog._attrs)
4

这是最后一条链:

< Buff行情>
>>> catalog._attrs = dict(catalog._attrs)
5

链的"cycled"属性具有创建循环的查询列表。 如果运行一个或多个查询,您将看到循环将 重新启动–路径将开始重叠的位置。有时是质疑 结果将包括多个循环,以及一些非循环的路径。 在本例中,只有一个循环查询,结果是 循环关系。

< Buff行情>
>>> catalog._attrs = dict(catalog._attrs)
6
>>> catalog._attrs = dict(catalog._attrs)
7

消除这种疯狂"id="id13" rel="nofollow">[12],我们可以取消zane的索引,然后更改 重新索引爱丽丝。

[11]

对贝蒂、爱丽丝和赞恩的查询结果都是 同样的。

>>> catalog._attrs = dict(catalog._attrs)
0

循环不会污染循环外的索引。

>>> catalog._attrs = dict(catalog._attrs)
1
>>> catalog._attrs = dict(catalog._attrs)
2
< COL/> < COL/> <正文> < > <表>

可以找到

我们到了最后一个搜索方法: canfind 。我们得到了价值观 关系,但是如果你只是想知道 有联系吗?例如,爱丽丝是豪伊的主管吗?是 扔出?要回答这些问题,可以使用 canfind 方法 与 targetquery 搜索参数结合。

canfind方法的参数与findRelations相同。然而, 它只返回一个关于搜索是否有任何结果的布尔值。这个 是一种方便,还允许进行一些额外的优化。

贝蒂监督谁吗?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
4

豪伊呢?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
5

赞恩(不再是雇员)呢?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
6

如果我们想知道艾丽斯或查克是否监督豪伊 路径上两点的特征。问一个关于另一个的问题 在路径末尾,使用 targetquery

爱丽丝是豪伊的主管吗?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
7

查克是豪伊的主管吗?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
8

Howie Alice是他的雇员吗?

< Buff行情>
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
9

豪伊·查克是他的雇员吗?

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
0

(注意,如果您的关系描述了一个层次结构,则向上搜索层次结构是 通常比向下搜索更有效,所以第二对问题是 在这种情况下,通常比第一种更好。)

使用更复杂的关系

到目前为止,我们的示例使用了一个简单的关系,其中索引对象 是关系的一端,对象上的索引值是另一端。 这个示例让我们查看了所有基本的zc.relation目录 功能。

不过,正如引言中提到的,目录支持 为更复杂的关系而设计。本节将快速检查 很少有其他用途的例子。

在本节中,我们将看到上面提到的一些想法的例子,但不是 但已演示。

  • 我们可以使用接口属性(values或callables)来定义值 索引。
  • 使用接口属性将导致尝试调整关系,如果 尚未提供接口。
  • 在定义值索引时,我们可以使用 multiple 参数来指示 索引值是一个集合。
  • 在定义值索引时,我们可以使用 name 参数来指定 要在查询中使用的名称,而不是依赖于接口的名称 属性或可调用。
  • 在实例化catalog中的 family 参数允许您更改 关系和值索引的默认btree系列 btrees.family32.if btrees.family64.if

外部双向关系

我们当前故事的一个简单变化是:如果索引关系 在另外两个物体之间——也就是说,如果关系是外在的 两个参与者?

假设我们有亲生关系。我们想要一个 "人"和"父母"关系。我们将为 iparentage 因此我们可以看到如何使用接口定义值索引 作品

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
1

现在我们将定义转储程序和加载程序,然后定义目录。通知THAT 我们依赖一种模式:在加载之前必须调用转储。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
2

现在我们有一个完整的目录。让我们添加一些关系。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
3
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
4

这是我们的一个层次结构图。

>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
5

现在,我们可以索引这些关系,并提出一些问题。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
6

多方向关系

上一个例子很快展示了如何为 外在的双向关系。相同的模式可以扩展为n路 关系。例如,考虑一个四向关系 主谓宾语[在上下文中]。例如,我们可以 想说"(乔,)在街角的商店里卖(甜甜圈,咖啡),"(乔,)" 是主语的集合,"sells"是谓语,"(甜甜圈,咖啡)" 是对象的集合,"corner_store"是可选上下文。

对于最后一个例子,我们将集成两个我们还没有看到的组件 以前的版本:zodb和改编版。

我们的示例zodb方法使用oid作为令牌。这可能在一些 如果您永远不支持多个数据库,并且不需要 抽象层,以便不同的对象可以具有相同的标识符。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
7

(使用zope.component时, \u conform\uuu 通常是不必要的; 但是,此包不依赖于zope.component。)

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
8
>>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
...                       btree=BTrees.family32.OI)
9

如前所述, dumppersistent loadpersistent 有点像玩具 上面。另外,虽然我们的谓词将存储为字符串,但是一些程序员 在这种情况下,可能更喜欢使用转储来验证字符串是否 以某种方式显式注册,以防止输入错误。显然,我们不是 为我们的例子而烦恼。

我们制造一些物体,然后我们与这些物体建立一些关系 为它们编制索引。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
0
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
1
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
2
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
3

现在我们可以问一个简单的问题。他们在哪里卖甜甜圈?

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
4

希望这些示例能为您提供有关如何使用此工具的进一步想法。

附加功能

本节介绍外围设备功能。我们将学习以下内容。

  • 侦听器可以在目录中注册。当一个亲戚 添加、修改或删除;清除并复制目录时 (见下文)。
  • clear方法清除目录中的关系。
  • copy方法通过复制内部目录来复制当前目录 数据结构,而不是重新索引关系,它可以是 重大优化机会。这将复制值索引并搜索 索引;并给侦听器一个机会来指定 应该包含在新副本中。
  • 五种相关搜索方法的ignoresearchindex参数 使搜索忽略搜索索引,即使有适当的 一个,
  • findRelationTokens() (不带参数)返回所有 目录中的关系标记。
  • findValueTokens(index_name) (其中"index_name"应替换为 索引名)返回目录中所有值标记的btree集 给定的索引名。

听众

当目录发生更改时,可能会有多种潜在的客户端需要得到警报。 zc.relation不依赖于zope.event,因此可以注册侦听器 各种变化。让我们做一个快速的演示监听器。 加法 removals 参数是{value name:iterable of added or的字典 远离的值标记}。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
5

监听器可以多次安装。

侦听器可以作为持久弱引用添加,因此,如果它们是 在其他地方删除后,zodb包将不考虑目录中的引用 防止垃圾收集。

我们将把其中一个演示监听器作为 正常引用,默认行为。然后我们将展示一些示例消息 发送到演示侦听器。

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
6
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
7

这些示例中没有显示的两个方法是 sourcecleared 已复制源代码 。我们很快就会看到下面的内容。

清除方法

clear方法只对目录中的所有关系进行索引。安装 侦听器已调用 sourcecleared

< Buff行情>
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
8
>>> catalog.addValueIndex(supervisor, dumpEmployees, None,
...                       btree=BTrees.family32.OI, name='supervisor2')
Traceback (most recent call last):
...
ValueError: either both of 'dump' and 'load' must be None, or neither
9 α
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
00
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
01

复制方法

有时可能需要复制关系目录。一种方法是 若要创建新目录,请将其设置为当前目录,然后重新编制索引 同样的关系。这对程序员来说是不必要的慢,而且 计算机。copy方法用相同的 通过复制内部数据结构建立索引关系。

搜索索引被请求为新的 catalog;并且监听器有机会根据需要对新的 复制,包括安装它们自己和/或它们选择的另一个对象 作为听众。

让我们制作一个包含搜索索引和侦听器的填充索引的副本。 注意,在我们的侦听器中, sourcecopied 将自己作为侦听器添加到 新副本。这是在复制过程的最后完成的。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
02
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
03

现在,该副本拥有自己的内部数据结构和 搜索索引。例如,让我们修改关系并将新关系添加到 复制.< /P> < Buff行情>

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
04

原始目录未被修改。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
05

参数 ignoresearchindex 参数

可以使用搜索索引的五种方法, findValue findValueTokens findRelations findRelationTokens ,以及 可以显式地请求canfind忽略任何相关的搜索索引 使用 ignoresearchindex 参数。

我们可以通过与令牌相关的方法很容易地看到这一点:搜索索引结果 将是一个btree集合,而如果没有搜索索引,则结果将是 发电机。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
06
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
07

我们可以看到其他方法接受这个参数,但是结果看起来 与往常一样。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
08
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
09
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
10

findrelationtokens()

如果在没有任何参数的情况下调用findrelationtokens,您将得到 目录中所有关系标记的树集。这对测试很方便 以及目录的高级使用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
11

FindValueTokens(索引名)

如果只使用索引名调用findValueTokens,将得到btree 索引中该值的所有标记的结构。这很方便 测试和目录的高级使用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
12

结论

回顾

这就结束了我们的介绍我举个例子。让我们回顾一下 然后看看你可以从这里走到哪里。

  • 关系是具有索引值的对象。

  • 关系目录索引关系。这种关系可以是单向的, 双向、三向或N向,只要告诉目录为 不同的值。

  • 创建目录:

    < Buff行情>
    • 关系及其值作为标记存储在目录中:唯一 可以解析回原始值的标识符。整数是 最有效的代币,但其他代币也可以正常工作。

    • 令牌类型决定所需的btree模块。

      < Buff行情>
      • 如果令牌是32位整数,请选择 btrees.family32.ii btrees.family32.if btrees.family32.io
      • 如果令牌是64位整数,请选择 btrees.family64.ii btrees.family64.if btrees.family64.io
      • 如果它们是其他的,请选择btrees.family32.oi, btrees.family64.oi btrees.family32.oo (或 btrees.family64.oo–它们是相同的。

      在这些规则中,选择有些武断,除非您计划 将这些结果与使用 特定的btree模块。btree set操作只在同一个 模块,因此您必须将模块与模块匹配。

    • 在实例化catalog中的 family 参数允许您更改 关系和值索引的默认btree系列 btrees.family32.if btrees.family64.if

    • 必须定义自己的标记化和解析标记的函数。 这些函数在关系和 它们的每个值索引。

    • 您可以向关系目录添加值索引,以便能够进行搜索。价值观 可通过可调用项或接口元素标识到目录。

      < Buff行情>
      • 使用接口属性将导致尝试调整 如果尚未提供接口,则为关系。
      • 在将值索引定义为 指示索引值是集合。默认为 错误。
      • 在将值索引定义为 指定要在查询中使用的名称,而不是依赖于 接口属性或可调用的名称。
    • 您可以设置搜索索引来加速特定的搜索,通常 可传递。

    • 侦听器可以在目录中注册。当 关系被添加、修改或删除;当目录被清除时 并复制。

  • 目录管理:

    < Buff行情>
    • 关系用索引(关系)索引,并从 目录中有 未索引(关系) 索引文档(关系令牌, 关系) 取消索引文档(关系令牌) 也可以工作。
    • clear方法清除目录中的关系。
    • copy方法通过复制来复制当前目录 内部数据结构,而不是重新索引关系,这可以 成为一个重要的优化机会。这将复制值索引和 搜索索引;并使侦听器有机会指定 任何内容,都应包含在新副本中。
  • 搜索目录:

    < Buff行情>
    • 对关系目录的查询由dict组成。

    • 查询键是要搜索的索引的名称,或者 精确关系的特殊情况,即 zc.relation.relation 常数。

    • 查询值是要匹配的结果的标记;或者 ,表示将 作为值(或空)的关系 集合(如果是倍数)。搜索值可以使用 zc.关系catlog.any(args) zc.relation.catalog.any(args) 到 指定多个(non- none )结果以匹配给定的密钥。

    • 索引有多种方法可帮助您使用标记。 tokenizequery 通常是最常用的,尽管其他的是 可用。

    • 要查找与查询匹配的关系,请使用 findRelations FindRelationtokens 。调用不带任何 参数返回目录中所有关系标记的树集。

    • 要查找与查询匹配的值,请使用 findValues findValueTokens 。仅使用名称调用findValueTokens 返回目录中所有令牌的btree集 价值指数。

    • 您可以使用查询工厂进行传递性搜索。这个 zc.relation.queryfactory.transportingtransitive 是一个很好的常见情况 允许您在层次结构中上下移动的工厂。查询工厂可以 作为搜索方法的参数作为queryfactory传入,或 作为默认行为安装,使用 addDefaultQueryFactory

    • 要查找查询的关联方式,请使用 findRelationChains FindRelationtokenchains

    • 要确定查询是否相关,请使用 canfind

    • 循环传递关系被处理以防止无限循环。他们 在 findrelationchains findrelationtokenchains 中确定 带有一个 zc.relation.interfaces.icircularrelationpath 标记接口。

    • 搜索方法共享以下参数:

      • 最大深度 ,限制搜索的传递深度;
      • 过滤,允许代码过滤可传递路径;
      • targetquery ,允许查询筛选 端点的基础;
      • targetfilter ,允许代码根据 终点;和
      • 上述queryfactory

      此外, findRelations ignoresearchindex 参数, FindRelationTokens FindValues FindValues标记 ,以及 canfind导致搜索忽略搜索索引,即使存在 一个合适的。

下一步

如果你想读更多的书,接下来的步骤取决于你喜欢怎样学习。在这里 是zc.relation包中的一些其他文档。

<表> < COL/> < COL/> <正文>
< > <表>

最后,真正的死难者也可能对时间感兴趣 目录,其中包含用于测试假设和学习的脚本。

[12]

如果你想,看看当你去 其他方式:

>>> catalog._attrs = dict(catalog._attrs)
8
>>> catalog._attrs = dict(catalog._attrs)
9
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
0
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
1
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
2
>>> def supervisor(emp, catalog):
...     return emp.supervisor # None or another employee
...
3
优化。rst:
优化关系目录使用的最佳实践。
搜索索引。rst:
查询工厂和搜索索引:从基础到细节。
令牌。rst: 本文档探索令牌的详细信息。全神的辣椒 爱情信物,至少如果上帝的奇伦在写非玩具应用程序 使用zc.relation。它包括对令牌助手的讨论 目录提供了如何使用zope.app.intid-like注册表 关系,如何使用令牌合理地"连接"查询结果 以及如何索引连接。这也是不必要的 因为所用的例子,令人心驰神往。
接口。py: 螺母和螺栓的合同。
< COL/> < COL/> <正文> < > <表>

标记和联接:zc.关系目录扩展示例

介绍和设置

本文档假设您已经阅读了介绍性的readme.rst并希望 以身作则。在它中,我们将探索 一组复杂的关系,展示了 使用代币。特别是,我们将研究连接,它将 也让我们有机会更深入地了解查询工厂和 搜索索引,并引入侦听器的思想。它无法解释 自述文件中已经提到的基础知识。

假设我们正在为系统中的安全断言编制索引。在这 系统中,用户可能在组织中具有角色。各组织 可能有多个子组织,也可能只有一个父组织 组织。在父组织中具有角色的用户将具有 在所有传递连接的子关系中扮演相同的角色。

我们有两种关系。一种关系将模型 组织的等级制度。我们用一个内在的关系 组织对孩子的影响:这反映了一个事实 组织选择并由他们的孩子组成;孩子选择 不要选择父母。

另一个关系将为(单个)用户具有的(多个)角色建模 在一个(单一)组织中。这种关系完全是外在的。

我们可以创建两个目录,每种类型一个。或者我们可以把它们 都在同一个目录中。最初,我们将使用单个目录 我们的例子。那么,这个目录将为 关系的异构集合。

让我们用接口定义这两种关系。我们将包括一个 访问器,getorganization,主要用于显示如何处理方法。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
13

现在我们可以创建一些类。在自述示例中,设置有点 玩具的这次我们会更实际一点。我们也会期待 在zodb中操作,有根和事务。 [14]

[13]

好的,您关心查询工厂是如何工作的,所以 我们会调查一下的。让我们通过两个步骤来讨论 第二个问题中的传递搜索。最初的目录 执行请求的初始不及物搜索:查找关系 贝蒂是他们的主管。那是黛安娜和埃德加。

现在,对于每个结果,目录都要求查询工厂 下一步。我们带黛安娜去吧。目录对工厂说, "考虑到贝蒂是主管的关系问题,我得到了 这是黛安娜的结果。你还有其他问题要问吗 再往前看?"。工厂还获取目录实例,因此 如果需要,可以用它来回答问题。

好吧,下一部分是你的大脑受伤的地方。坚持住,

在我们的例子中,工厂看到查询是针对主管的。它的 另一个键,它所转换的键是 zc.relation.relation 。< EM > factory获取当前令牌的转置密钥结果。so,for us, zc.relation.relation 的一个键实际上是一个no op:结果 现在的代币,黛安娜。然后,工厂有了自己的答案:更换旧的 查询中的supervisor值betty,结果为diane。下一个 传递查询应该是{'supervisor','diane'}。TA D. < /P>

< COL/> < COL/> <正文> < > <表>

我们将如何转储和加载关系:使用"注册表" 对象,类似于intid实用程序。 [15]

[14]

这里我们将设置一个zodb实例供我们使用。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
14
< COL/> < COL/> <正文> < > <表>

在这个"dump"方法的实现中,我们使用缓存来 告诉你如何使用它。这工作可能有点过分了, 甚至可能会失去速度,但你可以看到这个想法。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
18

现在我们可以创建一个关系目录来保存这些项目。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
19

现在我们建立索引。我们从组织开始,然后 用它们建立目录。这部分将类似于示例 在readme.rst中,但是将引入更多关于优化和 令牌。然后我们将添加关于角色的部分,并探索查询和 基于令牌的"连接"。

组织

组织将拥有一组组织。这实际上不是 在zodb中本来就很容易,因为这意味着我们需要比较 或者散列持久对象,这些对象随着时间的推移不能可靠地工作,并且 把机器从盒子里拿出来。为了回避这个例子的问题, 还是做一些有点意思的真实的事情,我们会用 上面介绍的注册表标记。这也会给我们一个机会 再多谈谈优化和令牌。(如果你愿意 要以理智和透明的方式保存一组持久对象,请尝试 尚未设置包xxx。)

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
20

好的,现在我们知道组织将如何运作。现在我们可以添加 部分 目录索引。这将从我们添加的 自述文件中的索引。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
21

那么,与自述示例有什么不同?

首先,我们使用一个接口元素来定义要索引的值。 它提供了一个接口,对象将被适应,一个默认名称 对于索引,以及有关是否应使用该属性的信息 直接或致电。

其次,我们没有指定转储或加载。他们没有。这个 意味着索引值已被视为标记。这个 如果索引为 值是使用与 索引–这将引出下一个差异。

第三,我们指定 multiple=true 。这意味着 在一个给定的关系上,提供或能够适应组织将 收集 部分。这些永远都是一套, 实际colection是btrees集还是btree的键。

最后,我们指定一个用于查询的名称。我发现这些疑问 当查询键是单数时更容易阅读,因此我经常重命名复数。

在自述文件中,我们可以添加另一个简单的转置传递查询 工厂,在"部分"和"无"之间切换 < Buff行情>

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
22

让我们在查找的层次结构中添加几个搜索索引…

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
23

…向下。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
24

请注意:搜索索引实际上不是一个好主意。这个 索引是为向下查找而设计的。

[15]

这里有一个简单的持久密钥引用。注意它是 不是持久的:这对解决冲突很重要 能够工作(我们在这里没有展示,但我们试着靠得更多 走向实用对于本例)。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
15

这是一个简单的整数标识符工具。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
16
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
17
< COL/> < COL/> <正文> < > <表>

让我们创建并添加一些组织。

我们将创建这样的结构

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
26

这是蟒蛇。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
27

现在目录知道了这些关系。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
28

而且,现在我们可以搜索了。为此,我们可以使用一些 T他提供目录。最常用的是tokenizequaly。它需要一个 使用未标记化的值进行查询并将其转换为 标记化。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
29

当然,现在单独用"part"做这个有点傻,因为 不会在关系目录中更改(因为我们说过dump和 负荷 ,如上所述。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
30

tokenizequery方法非常常见,我们将把它分配给 我们例子中的变量。然后我们将进行一两次搜索。

所以…找出YNOD开发人员管理的关系。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
31

好吧…我们使用了findrelationtokens,而不是findrelations,所以 现在是几个数字。我们如何将它们转换回来? ResolveRelationTokens 将起作用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
32

resolvequery 是tokenizequaly的镜像:它转换 标记化查询到具有"加载"值的查询。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
33
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
34

同样, tokenizerelations resolvereationtokens 的镜像。 < Buff行情>

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
35

其他与令牌相关的方法如下 [17]

[16]

transmissingTransitiveMembership索引 提供ISearchindex。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
25
< COL/> < COL/> <正文> < > <表>
  • tokenizevalues ,它返回值的一个iterable标记 给定索引名的;
  • resolveValueTokens ,它返回 给定的索引名;
  • 标记化 ,返回给定关系的标记;和
  • ResolveRelationToken ,它返回给定令牌的关系。

为什么我们要用这些代币,而不是把它们藏起来 使api更漂亮?通过曝光它们,我们可以实现高效的连接, 以及在其他情况下的有效使用。例如,如果您使用相同的 intid实用程序在其他目录中标记,我们的结果可以合并 其他目录的结果。同样,您可以使用结果 对其他目录的查询-甚至从 正在查询此目录-作为此处的查询值。我们将在 下一节。

角色

我们已经建立了组织关系。现在让我们设置角色,然后 实际上能够回答我们在开头描述的问题 文件的。

在我们的roles对象中,roles和principal只是字符串–id,如果 这是一个真正的系统。组织将是直接的对象引用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
40

现在,让我们将值索引添加到关系目录中。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
41

这些是我们在 addvalueindex 以前,但所有的混合和匹配相同的成分。

提醒一下,我们的组织结构如下:

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
26

现在,让我们创建并添加一些角色。

< Buff行情> αααα143

现在,我们可以开始进行搜索了。

[17]

对于它的价值,这里有一些小的 其余令牌相关方法的示例。

这两个是 tokenizerelations 解决关系令牌

标记化 返回给定关系的标记。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
36

ResolveRelationToken 返回给定令牌的关系。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
37

现在"价值观"的表现有点蹩脚,因为唯一的价值观 我们现在没有标记化,而是直接使用。但是这里 去,显示一些迷人的禁止操作。

tokenizevalues ,返回 给定的索引名。

αααα138

resolveValueTokens 返回 给定的索引名。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
39
< COL/> < COL/> <正文> < > <表>

奥菲莉亚的角色设置是什么?

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
45

这个答案不需要传递:我们完成了。

下一个问题。奥菲莉亚在哪里扮演"作家"的角色?

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
46

好吧,这是不及物的。我们需要传递查询吗 工厂?不!这是一个很好的机会来看看我们谈过的 关于上一节。这实际上应该是两个步骤 行动:找到所有奥菲莉亚有作家的组织, 然后找到该组织的所有可传递部分。

< Buff行情> αααα147

更像是这样。

下一个问题。哪些用户在"zookd devs"组织中有角色? 不及时性,这很容易。

< Buff行情> αααα148

在传递性方面,我们应该执行另一个连接。

< Buff行情> αααα149

这有点尴尬,但它确实起到了作用。

< dl >
最后一个问题,以及开始整个示例的问题。

奥菲莉亚在"Zookd NBD"组织中扮演什么角色?

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
50

不及时性,这是正确的。但是,从传递的角度来说,奥菲莉亚也有 评论员和作者,这是我们希望能够快速得到的答案。

我们可以用另一种方式来提问,然后,再次利用join。 我们将它设置为一个函数,因为我们稍后将要使用它 不重复代码。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
51

如您所见,使用令牌使有趣的连接成为可能, 只要两个查询中的标记相同。

我们已经研究了标记方法和标记技术,比如连接。实例 我们讲的故事可以让我们进入一些更高级的话题,比如 查询工厂连接并搜索可以提高读取速度的索引。

查询工厂连接

我们可以建立一个查询工厂,使连接自动进行。查询 factory是一个带两个参数的可调用函数:一个查询 开始搜索)和目录。工厂要么不退货, 指示查询工厂不能用于此查询,或 返回另一个接受关系链的可调用函数。最后 关系链中的令牌是最新的。这个的输出 内部可调用的 btrees.family32.oo.bucket查询以从给定链进一步搜索 关系的。

这是解决这个问题的一个有缺陷的方法。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
52

这对我们当前的示例有效。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
53

但是,对于其他类似的查询,它将不起作用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
54

有缺陷的工厂实际上是更典型的关系的有用模式 遍历。从一种关系到另一种关系,奥菲莉亚 一直到高层都有联系。然而,安倍只有 顶部,因此没有任何东西被遍历。

相反,我们可以创建一个查询工厂来修改初始查询。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
55
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
56
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
57

这种方法和另一种方法的区别在于 不及物的:这个查询工厂修改初始查询,然后 不要再问了。目录当前总是停止调用 如果查询不返回任何结果,因此 有缺陷的工厂根本无法解决此类问题。

我们可以将此查询工厂添加为另一个默认值。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
58
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
59
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
60

以前安装的查询工厂仍然可用。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
61
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
62
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
63

查询工厂联接的搜索索引

现在我们已经编写了一个封装连接的查询工厂,我们可以 使用加快搜索速度的搜索索引。我们只使用传递搜索 迄今为止的索引。现在我们将添加一个不及物搜索索引。

不及物搜索索引通常只需要搜索值 名称应该是索引,结果名称(默认为 关系),并且可以选择要使用的查询工厂。

我们需要使用两个额外的选项,因为我们是 做。我们需要指定组织和主体id值需要什么 当对象被索引时被更改,并且我们需要指出 应在组织、负责人id、 部件更改时更新。

getvaluetokens 指定需要索引的值。它得到 索引、所需令牌的名称、令牌、目录 生成了令牌更改(它可能与索引的 catalog,包含值字典的源字典 如果不重写标记,则将用于标记 此标记的附加值(键是值名),是 已删除此标记的值,以及是否已删除该标记。 方法不能返回none,这将使索引保留为默认值 在没有使用查询工厂的情况下应该有效的行为;或者 值:

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
64
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
65
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
66
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
67

[19]

[18]

我们还可以更多地显示值标记方法 现在清醒。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
44
< COL/> < COL/> <正文> 不及物搜索索引提供 iArchindex和iListener。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
68 < > <表>

现在我们可以改变和消除关系,包括组织和角色 使索引保持正确状态。考虑到 组织–

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
26

–首先,我们将把ynod dev移到zookd dev下面,然后退出。本遗嘱 简要地给予Y3L4项目和其他项目ABE完全特权。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
70

作为另一个例子,我们将改变安倍的角色,并看到它是 向下传播到zookd nbd。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
71
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
72

请注意,搜索索引顺序很重要。在我们的例子中,我们的不及物搜索 索引依赖于我们的传递索引,因此传递索引需要 先来。在名称之前需要可传递关系索引。马上, 你负责这个订单,很难想出一个 可靠的猜测算法。

侦听器、目录管理和跨关系目录加入

到目前为止,我们已经用一个索引目录完成了所有示例 两种关系。如果我们想要两个目录 同质的关系集合?感觉很干净,但也很干净 引入一些新的皱纹。

让我们使用当前的组织目录,删除多余的 信息;并为角色创建一个新角色。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
73

我们需要一个稍微不同的查询工厂和一个稍微不同的 搜索索引 getvaluetokens 函数。我们将编写这些,然后修改 为新世界配置两个目录。

我们在这里编写的可传递工厂用于角色目录。资讯科技成功 访问组织目录。我们可以做很多 方法-依赖实用程序,或从上下文中查找目录。我们将 使角色目录具有.org目录属性,并依赖该属性。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
74
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
75

如果你在代码中跟随并与原件进行比较,你可以 要知道,这种方法比关系 在同一目录中。

现在我们将修复组织目录

< COL/> < COL/> <正文> < > <表>

这还显示了如何使用RemoveDefaultQueryFactory和RemoveSearchIndex 方法

[20]

在我们修改它们之前,让我们看看我们制作的副本。 副本当前的行为应与原件相同。

αααα176
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
77
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
78
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
79
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
80
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
81 αααα182
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
83
< COL/> < COL/> <正文> < > <表>

现在我们将设置角色目录

[21]

通过删除查询会得到错误 未注册的工厂。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
84
< COL/> < COL/> <正文> 对一个副本的更改不应影响另一个副本。那 意味着角色目录仍应像以前一样工作。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
85
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
86
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
87
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
88 < > <表>

新的角色目录索引需要从组织目录更新。 我们将使用侦听器来设置,这是一个新概念。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
89

现在角色目录应该能够回答与旧目录相同的问题 单一目录法。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
90
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
91

我们还可以对目录和搜索索引进行更改 维护。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
92 αααα193
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
94

我们在这里添加一个新组织。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
95
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
96
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
97

现在我们将删除它。

< Buff行情>
>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
98

要确保不及物复制看起来与我们期望的一样

[23]

< COL/> < COL/> <正文> < > <表>
[23]

您可以多次添加侦听器。

>>> employees = {} # we'll use this to resolve the "name" tokens
>>> from functools import total_ordering
>>> @total_ordering
... class Employee(object):
...     def __init__(self, name, supervisor=None):
...         if name in employees:
...             raise ValueError('employee with same name already exists')
...         self.name = name # expect this to be readonly
...         self.supervisor = supervisor
...         employees[name] = self
...     # the next parts just make the tests prettier
...     def __repr__(self):
...         return '<Employee instance "' + self.name + '">'
...     def __lt__(self, other):
...         return self.name < other.name
...     def __eq__(self, other):
...         return self is other
...     def __hash__(self):
...         ''' Dummy method needed because we defined __eq__
...         '''
...         return 1
...
99

现在,我们将删除侦听器,以显示我们的能力。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
00

删除我们没有的搜索索引也一样

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
01
< COL/> < COL/> <正文> < > <表>

使用搜索索引:zc.relation catalog扩展示例

简介

本文档假设您已经阅读了readme.rst文档,并希望了解 再举个例子。在书中,我们将探讨一组关系 演示使用搜索索引和侦听器的大多数方面。 它不会解释其他文件已经涉及的主题。它 还描述了一个高级用例。

正如我们在其他文档中看到的,关系目录支持 搜索索引。它们可以根据需要返回任何搜索的结果。 当然,其目的是提供一个索引来优化 它声称的特定搜索。

searchindex模块提供一些搜索索引,优化 指定传递和不传递搜索。我们看到他们在工作 在其他文件中。我们将在本文档中对它们进行更深入的研究。

搜索索引通过"侦听器"接收消息来更新自身 接口。我们还将了解它的工作原理。

此文件中描述的示例检查类似于 zc.revision或zc.vault包:关系描述了 其他物体。因此,这是我们第一个 外部关系。

让我们建立一个例子故事一点。假设我们有一个图表,通常是 标记的层次结构-整数。关系指定给定的整数 令牌与其他整数令牌相关,包含表示或 其他含义。

整数还可以具有指定它们表示 一个或多个对象。

这允许我们有一个对象图,其中更改 图表不需要更改其余部分。因此,zc.revision和zc.vault 能够有效地为具有多个修订的图建模 有相当多的元数据支持合并。

让我们想象一个简单的层次结构。关系具有 标记 属性 还有一个 children 属性;children指向标记。关系会 用身份证证明自己。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
02 αααα203
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
04

标准TransportingTransitioneQueriesFactory将能够处理此问题 很好,所以我们用它作为索引。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
05

现在,让我们快速创建一个层次结构并将其索引。

< Buff行情> αααα206

[25] 该层次结构是任意的。以下是我们的代币 指向子对象:

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
07

12个关系,标记0到11,总共33个标记, 包括孩子们。12个关系的id是100到111, 对应于0到11的标记。

没有可传递的搜索索引,我们可以得到所有可传递的结果。 结果是迭代器。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
08 αααα209

[26] 也可以进行转换,并且将 使用可传递的搜索索引,如下所示。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
10

FindRelationtokenChains 不会改变,但我们会将其包含在 讨论和示例来说明这一点。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
11

可传递的搜索索引

现在我们可以添加几个传递搜索索引。我们来谈谈 先说一点。

目前有一种传递索引,它将 转换传递查询的关系和值搜索 工厂。

索引只能在特定条件下使用。

< Buff行情>
  • 搜索不是对关系链的请求。
  • 它没有指定最大深度。
  • 不使用过滤器。

如果是值搜索,则在 使用目标筛选器或目标查询,但基本关系索引可以 在这种情况下仍然使用。

搜索索引的使用在很大程度上是透明的:设置它们,以及 关系目录将它们用于使用更多 以前是蛮力。与外部用途的唯一区别是 使用索引的结果通常是btree结构,而不是 迭代器。

为关系添加可传递索引时,必须指定 查询的可传递名称(或名称),反之亦然。 这就是我们现在要做的一切。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
12

现在我们应该安装一个搜索索引。

注意我们是从父母那里(托克n)对儿童:该指数主要是 旨在帮助在层次结构中传递成员身份搜索。用它来 索引父项将为不太成功而招致大量写开销。

您可以在这里指定更多内容:查询的静态字段 做一些过滤。在这个例子中,我们不需要这些。

现在,目录如何使用此索引进行搜索?三种基本方式, 根据搜索的类型、关系、值或 canfind 。 在我们开始调查内部结构之前,让我们验证一下 我们期望的是:正确的答案,而不是迭代器,而是树结构。

< Buff行情> αααα213
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
14
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
15

[27] 注意,最后两个 可以从 当我们浏览这些没有索引的示例时,不要使用 索引,所以我们不在这里显示它们:它们看起来方向不对 此索引。

那么这些结果是如何发生的呢?

第一个, findrelationtokens 和最后一个, canfind 是最多的 直截了当。索引查找与给定的 查询,不及时性。然后为每个关系查找索引 该标记的传递结果。最终的结果是所有人的联合 从不及物搜索中找到的索引结果。 可以找到 将结果转换为布尔值。

findValueTokens 与上面的相同,只需再多做一步。后 计算关系的并集,该方法返回 为所有找到的关系设置请求的值。

当关系重新建立索引时,它将保持自身。

< Buff行情> αααα216
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
17
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
18 αααα219
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
20
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
21

复制索引时,将复制搜索索引。

< Buff行情> αααα222

帮助程序

在编写搜索索引和查询工厂时,通常需要完成 访问关系目录数据。我们已经看到许多这样的工具:

  • getrelationmoduletools 获取所需btree工具的字典 处理关系。

    < Buff行情>
    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    23

    只有当btree是i*或l*模块时,"multiunion"才存在。 使用zc.relation.catalog.multiunion助手函数执行 对于给定的工具集,您可以进行最佳组合。

  • getvaluemoduletools 对索引值也一样。

    < Buff行情> αααα224
    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    25
  • getrelationtokens 可以返回目录中的所有令牌。

    < Buff行情> αααα226

    这也恰好相当于一个空的 查询,

    αααα227

    它还可以返回与给定查询匹配的所有标记,如果 没有匹配项。

    αααα228

    这也恰好相当于查询的 findrelationtokens , 最大深度为1,没有其他参数。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    29

    除非没有匹配项, findrelationtokens 返回一个空 set(因此它总是返回iterable)。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    30
  • < DL>
    getvaluetokens 可以返回中给定值名称的所有令牌

    目录。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    31

    这与仅具有名称(或 空查询,最大深度为1)。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    32

    它还可以返回给定令牌的值。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    33

    这与catalog.findValueTokens相同,后者具有名称和查询 {无:标记}。

    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    34

    除非没有匹配项, findValueTokens 返回一个空 set(因此它总是返回iterable);而getvaluetokens将 如果关系没有值(或关系未知),则返回none。

    αααα235
    >>> def dumpEmployees(emp, catalog, cache):
    ...     return emp.name
    ...
    
    36
    < DL> 屈服关系ntokenchains是使用a的搜索的搜索主力

    查询工厂。待办事项:描述。

[24] 在《2001:太空漫游》中,许多人相信哈尔这个名字 被选中是因为它是IBM的Rot25…我有时会作弊 使用rot1,因为结果听起来更好。
< COL/> < COL/> <正文> < > <表>
[25]

查询工厂知道何时不需要它–不仅如此 当它的两个名字都没有被使用,而且当它的两个名字都是 使用。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
37
< COL/> < COL/> <正文> < > <表>
<当值与它们的令牌相同时, findValues 返回与 findValueTokens 相同的结果。在这里 我们看到这个没有索引。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
38
< COL/> < COL/> <正文> 再次,当值与其令牌相同时, findValues 返回与 findValueTokens 相同的结果。在这里 我们可以通过索引看到这一点。

>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
38 < > <表>

优化关系目录的使用

在以下方面有一些最佳实践和优化机会 目录。

  • 尽可能使用带整数键的btree集。他们可以用树 多联合 以提高速度。整数cmp是可靠的,在c中。
  • 永远不要使用持久对象作为键。它们将导致 当您需要查看它们时,它们占用内存和对象缓存,并且 他们(截至本文撰写时)禁用冲突解决。Intids(或类似) 是表示对象的最佳选择,以及一些其他不可变的,如 字符串是下一个最佳匹配,zope.app.keyreferences(或类似的)是 之后。
  • 尽可能在查询中使用多个标记值,特别是在 传递查询工厂。
  • 在加载和转储令牌时使用缓存,并在 传递查询工厂。
  • 如果可能,不要加载或转储令牌(可以使用值本身 作为标记)。当您有多个令牌时,这一点尤其重要: 将它们存储在与zc.relation模块相同的模块中的btree结构中。 价值。

对于某些操作,特别是在 单个关系值,其中一些优化可以加快 常见情况下,重新编制索引的工作次数约为100次。

最简单(也可能最不有用)的优化是 单个操作生成的调用和所有加载调用共享一个缓存 每个调用类型的字典(转储/加载),每个索引关系值。 因此,例如,我们可以保存intids实用程序,以便 只需执行一次实用程序查找,此后它只 单字典查找。这是默认的 generatetoken resolvetoken 函数在zc.relationship的index.py do中:查看它们 例如。

进一步的优化是根本不加载或转储令牌,而是使用值 那可能是代币。如果令牌具有 _ c语言中的cmp_uuu(或等效的),如ints之类的内置类型。指定 此行为将创建一个索引,其中包含 索引属性描述显式设置为"无"。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
40
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
41
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
42
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
04
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
44
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
45
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
46

如果你有成百上千的关系 对象,如果值是相同的"倍数",则可能是一个巨大的胜利 键入作为给定属性的存储btree。默认btree 属性的族是ifbtree;iobtree也是一个不错的选择,并且可以 在某些应用中更受欢迎。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
47

重新编制索引是可以实现一些重大改进的地方。以下 回转操作优化代码。

BLOCKQuo>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
48
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
49
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
50
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
51
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
52
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
53

TokenIzeValues和ResolveValueTokens在没有加载程序和 翻车机-也就是说,它们什么也不做。

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
54

更改

1.1.post2(2018-06-18)

  • 另一次尝试使用正确的预期元数据语法修复PYPI页。

1.1.post1(2018-06-18)

  • 使用正确的rest语法修复pypi页面。

1.1(2018-06-15)

  • 添加对Python3.5和3.6的支持。

1.0(2008-04-23)

这是zc.relation包的初始版本。然而,它 表示另一个包zc.relationship的重构。这个 包仅包含关系(发货)索引的修改版本, 现在称为目录。zc.relationship索引的重构版本 依赖于(子类)此目录。ZC.关系也保持 向后兼容的子类。

这个包只依赖于zodb、zope.interface和zope.testing 软件,可以在标准zodb数据库内部或外部使用。 不过,软件必须在那里(软件包非常依赖 在zodb btrees包中)。

如果要将旧的zc.relationship索引切换到 关系目录,在你的generations脚本中试试这个技巧。 假设旧索引是 旧的 ,则应创建以下行 一个新的zc.relation目录,包含您的旧数据:

< Buff行情>
>>> def dumpEmployees(emp, catalog, cache):
...     return emp.name
...
55

为什么相同的基本数据结构现在称为目录?因为我们 暴露了改变数据结构的能力,以及 添加和删除是索引。把索引放进去是没有意义的 索引,但将索引放入目录中确实有意义。因此,A 更名诞生。

这个包中的目录与前面的有几个不兼容 关系索引和许多新特性。zc.relationship包 维护向后兼容的子类。以下讨论 将zc.relation目录与zc.relationship 1.x索引进行比较。

与zc.relationship 1.x索引不兼容

两大变化是方法名现在引用的是 关系 而目录的实例化方式略有不同 从索引中。其他一些变化值得你注意。这个 下面的列表试图突出显示所有不兼容项。

<表> < COL/> < COL/> <正文>

< > <表>

更改和新功能
  • 目录现在提供了索引 搜索。索引必须显式实例化和注册 你想优化。当搜索值时,当 搜索关系,或确定两个对象是否 链接的。它不能用于关系链。请求索引 通常需要权衡更大的存储空间和更慢的写入速度 加快搜索速度。注册搜索索引已完成 在实例化时间之后;您可以迭代当前设置 使用,并移除它们。(代码路径希望支持遗留的 所有这些api的关系索引实例。)
  • 现在可以在创建目录后指定新值,重复 超过所使用的设置,然后删除值。
  • 目录有一个复制方法,可以在没有实际操作的情况下快速创建新的副本 必须重新建立关系索引。
  • 查询参数现在可以通过 使用zc.relation.catalog.any(1、2、3、4)或 zc.relation.catalog.any((1,2,3,4))。
  • 目录支持通过传递callables而不是 接口元素(仍受支持)。
  • findrelations 和新方法 findrelationtokens 可以找到 传递和不传递的关系。 芬兰 当以非及时性方式使用时,重复旧的zc.relationship索引 findrelationtokenset的行为。 ( findrelationtokenset 保留在api中,而不是弃用 要 findValueTokenSet
  • 在findValues和findValueTokens中, query 参数现在是可选的。如果 在布尔上下文、所有值或值中,查询的计算结果为false 返回标记。值标记使用 基础btree存储。然后可以直接用于其他btree 操作。
  • 全新的文档。不幸的是,仍然不够好。
  • 该软件包大大减少了ZC的直接依赖关系。 它现在更明显是一个zodb工具,除了 zope.testing和zope.interface。
  • 侦听器允许对象侦听来自目录的消息(可以 直接使用,或用于触发事件。
  • 您可以使用zc.relation.relation…键来搜索关系。 真的没有别名。对不起的。但是嘿,用常量!我想是的 更具可读性。
  • tokenizequery(和resolvequery)现在接受关键字参数作为 普通dict查询的替代方法。这可以使构造查询 更吸引人一点(即, query=catalog.tokenizequery; res= catalog.findValues('object', 查询(subject=joe,predicate=owns)) )。

大不相容性:
  • FindRelationshipTokenSet FindValueTokenSet 重命名为 一些稍有不同的语义,如 getrelationtokens 获取值标记 。结果与 可以使用 findrelationtokens(查询,1) (其中1是maxdepth)。相同的 结果as findValueTokenSet(relToken,name) 可以通过 findValueTokens(名称,{zc.relation.relation:relToken},1)
  • FindRelations 取代了FindRelationships。新方法将使用 如果已设置DefaultTransitiveQueriesFactory且MaxDepth不是1,则为它。 它共享 findrelationchains 的调用签名
  • islinked 现在可以找到
  • 目录实例化参数已从旧索引更改。
    • 加载 转储 (以前的 加载rel 转储rel , 现在分别是实例化所必需的参数。
    • 唯一的选择自变量是 btree (was relfamily )和 系列 。现在指定要索引的元素 添加值索引
    • 还要注意, addvalueindex 默认为无加载和转储功能, 与旧的实例化选项不同。
  • 查询工厂不同。请参见接口中的iqueryfactory。
  • 它们首先获取(query、catalog、cache),然后返回一个getquerys 可调用的,获取重新链接并生成查询;如果查询 不匹配。
  • 它们还必须处理空的重新链接。通常这应该 返回原始查询,但也可以用于对 原始查询。
  • 它们不再被认为是可传递的查询工厂,而是 常规查询变异器。
中等:
  • 目录不再继承自 zope.app.container.contained.contained.
  • 索引要求zodb 3.8或更高版本。
小:
  • deactivatesets 不再是一个实例化选项(它已被破坏 因为一个zodb错误,正如 文档)。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
JavaCenter是JavaFX2中不可执行的窗格   java Docker将容器连接到本地数据库   java无法通过Spring从Redis获得正确的值   java为什么要将数组转换为列表再转换为数组   Java泛型在方法中放入字符串或整数参数   在Cloud Bigtable SDK中找不到java类   java Mavensiteplugin无法加载生成的源(Jaxb)   java GWT序列化和Appengine通道Api   PrintWriter out=new PrintWriter(sWriter)和PrintWriter out=response之间的java差异。getWriter()   空手道DSL中的javascript,在java参数调用中传递变量时如何转义单引号   windows 64位java可以与32位tomcat一起使用   为for循环| Java输入参数   java您可以更改SWT选项卡项的背景和/或前景颜色吗?   用java生成6位pin码   java如何从另一个通量中排除通量中的所有元素   java无法调用“javafx.scene.control.ComboBox.getItems()”,因为“Controller.getMyBox()”的返回值为null   将Java字符串与数组匹配时出现问题   java如何使用HttpsUrlConnection对SSL连接使用代理身份验证?   java如何检查XML元素是否包含CDATA?