3

我想在一个查询“标签”和“项目”中返回两个集合,其中每个标签可以有 0..many 项目。看起来如果我使用投影,它将假定一个包含两列而不是两个集合的集合,对吗?有没有更好的方法来运行这个搜索查询?

我越来越"the query response contains columns Tags, Items however ...anonymous type does not contain settable properties to receive this data"

var query =  client
    .Cypher
    .StartWithNodeIndexLookup("tags", "tags_fulltext", keyword)
    .Match("tags<-[:TaggedWith]-items")
    .Return((items, tags) => new 
    {
        Tags = tags.As<Tag>(),
        Items = items.As<Item>()
    });

var results = await query.ResultsAsync;

return new SearchResult
{
    Items = results.Select(x => x.Items).ToList(),
    Tags = results.Select(x => x.Tags).Distinct().ToList()
};
4

1 回答 1

4

选项1

场景:您想要检索与关键字匹配的所有标签,然后为每个标签检索每个项目(以仍将它们链接到标签的方式)。

首先,这一行:

.StartWithNodeIndexLookup("tags", "tags_fulltext", keyword)

应该:

.StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)

也就是说,身份不应该tagtags。这是因为该START子句产生一组节点,每个节点都是 a tag,而不是一组称为tags. 语义,但它使下一步的事情变得更简单。

现在我们调用它tag而不是tags,我们将MATCH子句更新为:

.Match("tag<-[:TaggedWith]-item")

这就是说“对于集合中的每个标签,去寻找附加到它的每个项目”。同样,“item”是单数的。

现在让我们返回它:

.Return((tag, item) => new 
{
    Tag = tag.As<Tag>(),
    Items = item.CollectAs<Item>()
});

在这里,我们将每个“项目”收集到一组“项目”中。我在该代码中对单数与复数的使用非常具体。

生成的 Cypher 表如下所示:

-------------------------
| tag      | items      |
-------------------------
| red      | A, B, C    |
| blue     | B, D       |
| green    | E, F, G    |
-------------------------

最终代码:

var query = client
    .Cypher
    .StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)
    .Match("tag<-[:TaggedWith]-item")
    .Return((tag, item) => new
    {
        Tag = tag.As<Tag>(),
        Items = item.CollectAs<Item>()
    });

不过,这不适合您SearchResult

选项 2

场景:您想检索与关键字匹配的所有标签,然后检索与这些标签中的任何一个匹配的所有项目,但您不关心将两者链接在一起。

让我们回到 Cypher 查询:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN tag, item

这将产生一个像这样的 Cypher 结果表:

--------------------
| tag      | item  |
--------------------
| red      | A     |
| red      | B     |
| red      | C     |
| blue     | B     |
| blue     | D     |
| green    | E     |
| green    | F     |
| green    | G     |
--------------------

您希望将其中的每一个都折叠成一个不相关的标签和项目列表。

我们可以collect这样做:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN collect(tag) AS Tags, collect(item) AS Items

-----------------------------------------------------------------------------
| tags                                            | items                   |
-----------------------------------------------------------------------------
| red, red, red, blue, blue, green, green, green  | A, B, C, B, D, E, F, G  |
-----------------------------------------------------------------------------

我们不希望所有这些重复,所以让我们收集不同的:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN collect(distinct tag) AS Tags, collect(distinct item) AS Items

--------------------------------------------
| tags              | items                |
--------------------------------------------
| red, blue, green  | A, B, C, D, E, F, G  |
--------------------------------------------

随着 Cypher 的工作,将其转换为 .NET 很容易:

var query = client
    .Cypher
    .StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)
    .Match("tag<-[:TaggedWith]-item")
    .Return((tag, item) => new
    {
        Tags = tag.CollectDistinct<Tag>(),
        Items = item.CollectDistinct<Item>()
    });

概括

  1. 始终从 Cypher 开始
  2. 始终从 Cypher 开始
  3. 当您使用 Cypher 时,.NET 实现应该几乎是一对一的

问题?

我已经在没有 VS 支持的文本框中输入了所有这些代码,而且我还没有测试过任何代码。如果发生崩溃,请在我们的问题页面上报告完整的异常文本和查询。在这里跟踪崩溃很困难。在没有完整异常文本、消息、堆栈跟踪等的情况下跟踪崩溃只会消耗我的时间,因为它会使调试变得更加困难,并且减少了我可以花在帮助您上的时间。

于 2013-03-28T01:28:17.503 回答