【问题标题】:Azure search return parent and child recordsAzure 搜索返回父子记录
【发布时间】:2017-10-05 00:28:19
【问题描述】:

我们的应用管理用户拥有的书籍,其中包含多个文档(pdf、word 文档等)。主页列出了用户的所有书籍,并带有一个用于加载接下来 10 本书的分页按钮。然后,当用户点击一本书时,它会在新屏幕中打开并列出该书的所有文档。

到目前为止,我们使用 WCF / 实体框架来检索主页上显示的所有书籍,然后使用 azure search(连接到 sql 视图)在打开一本书时获取它的文档,这与分页配合得很好和排序。

现在虽然我们还想从 azure 搜索中获取用户的所有书籍列表,所以我们创建了一个新表来保存书籍和文档数据,每个文档一行表示父书籍名称和书籍 ID 重复每一行。

AzureSearchTable

我们的 azure 搜索索引现在指向此表,我必须弄清楚如何通过分页和可能的排序为用户检索书籍。 问题是我需要对书籍进行不同的选择,但 azure search 并没有区别,而且我不知道一本书可能有多少文档,所以我不能将 Top 参数设置为 10。一本书可能有30 或 40 个文档,这意味着例如前 40 行可能只是一本书。

我尝试在书籍 id 上使用一个方面,哪种工作有效,并为我提供每本书的 id 和文档数量,但我似乎无法为方面指定排序顺序 - 顺序与我为查询设置的顺序(BookId)。我也不知道如何使用构面获取所有书籍 - 我可以在构面上设置计数属性,但我不知道用户将拥有多少本书。

我们的架构师说我应该获取所有行(可能是数千行)并在 C# 代码中过滤它们以获得 10 本书。不过,这对我来说似乎效率很低,而且感觉不对。

所以我不确定这是否是正确的方法..

  • 我是否应该为书籍和文档数据设置单独的 Azure 搜索索引(使用单独的表格?
  • 如何在不知道每本书有多少文档的情况下返回此表中前 n 本书?
  • 我可以使用 C# sdk 指定构面的排序顺序吗? (我认为可以通过其他 API 实现)
  • 如何获得一个方面来为用户归还所有书籍?

【问题讨论】:

    标签: sql-server azure-cognitive-search


    【解决方案1】:

    以下是一些想法:

    第 1 条答案:

    如果您的意图是能够根据 DocumentName 的搜索返回书籍列表,那么您可能希望将它们保留在同一个索引中。您的架构师关于在 C# 中处理结果的想法可能没有您想象的那么糟糕。您可以在 LINQ 中执行 GroupBy。 Azure 搜索查询很快,LINQ 查询也很快。特别是如果发出 Azure 搜索查询的计算机是 Azure Web/应用服务器并且位于同一区域(数据中​​心内通信)。即使使用 Suggestions API 来实现自动完成功能,我也使用了这种方法,该功能需要在用户输入时快速(在几百毫秒内)返回结果。我会说至少值得一试,看看您使用最大和典型数据集获得了什么样的性能。

    但是,如果这对您不起作用,那么请考虑重新构建索引架构,使 DocumentName 的类型为 Collection(Edm.String)。你会看起来像这样:

    {
        id: 20663,
        userId: 1,
        bookId: 2144,
        bookName: "ber",
        documentName: ["asdasd", "_318-1991.jpg", "wallhaven-13081.png", etc...],
        documentCount: 7
    }
    

    现在,如果您需要允许用户获取有关他们选择的特定图书的文档的详细信息,您可以通过调用数据库来获取图书详细信息。或者,您可以在此处为具有更详细文档信息的文档创建另一个 Azure 搜索索引。但是在用户工作流程的这一点上,除非您要在该特定书籍的文档中提供另一个全文搜索,否则您可能只想坚持使用 get-by-id 类型的 DB 调用。

    第 2 条答案:

    对于文档计数,您只需创建另一个字段(如上所示)并对其进行排序/过滤/构面。

    第 3 条答案:

    SDK 和 Azure 搜索 REST API 都没有提供对构面本身进行排序的方法,但请记住,您最终可以完全控制如何在 UI 中显示构面信息。如果 SDK 没有提供您需要的内容,您可以在您的应用程序中创建一个简单的查找类,以便按照您的喜好对构面进行排序。像这样的:

    public class FacetDefinition
    {
        public string FacetName { get; set; }
        public int FacetOrder { get; set; }
    }
    
    ...
    
    var myFacetDefinitions = new List<FacetDefinition>();
    myFacetDefinitions.Add(new FacetDefinition() { FacetName = "SomeNameThatMatchesTheFacetThatAzureSearchSendsBack", FacetOrder = 1});
    myFacetDefinitions.Add(new FacetDefinition() { FacetName = "SomeOtherNameThatMatchesTheFacetThatAzureSearchSendsBack", FacetOrder = 2});
    ...
    

    第 4 条答案:

    要返回特定用户的所有书籍,您只需添加一个过滤表达式,如下所示:

    userId eq <put_authenticated_userid_here>
    

    这是假设当前经过身份验证的用户应该只能看到他们自己的书籍。但是,如果您希望能够在一个方面拥有一个用户列表以过滤其中一个或多个用户,那么这将需要对索引模式进行另一次重组,以便在图书文档上有一个新字段,称为类似“用户”是用户名的 Collection(Edm.String)。像这样:

    {
        ...
        users: ["Luke Skywalker", "Han Solo", "Chewbacca", etc...]
        ...
    }
    

    【讨论】:

    • 嗨@Matthew 感谢您的更新。我为 Book 数据创建了一个新的搜索索引和一个新表,每本书一行,到目前为止一切正常。我读到了关于索引的 Collection(Edm.String) 类型,但它并不是很直观,至少对我来说不是。您认为使用这样的两个搜索索引有什么缺点吗?
    • 这取决于您必须搜索/过滤文档的哪些属性。您是否需要能够搜索/过滤 DocumentName 或文档的其他属性(例如文档的内容或类似内容)?
    • 是的,我们的文档表中还有很多其他文本字段,例如设备名称、位置地址、城市、街道等。所有这些字段都可以在索引中搜索(用于文档)。新表(用于图书)上的新索引将仅用于返回每本书的名称和 ID 以及每本书拥有的文档数。
    • Azure 搜索不支持排序方面。我已编辑问题以反映这一点。
    • @some_randomer 抱歉回复延迟。一般来说,为父实体和子实体拥有两个索引并不是一件坏事。事实上,有很多情况是必要的。这很大程度上取决于您需要如何返回搜索结果。例如,如果您需要能够同时搜索 Document 中的设备名称和 Book 的名称,或者搜索 Document 字段,然后根据 Book 属性进行过滤/分面,那么您至少需要一个索引将这两组数据拉到一起。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 2017-11-10
    • 2018-01-09
    相关资源
    最近更新 更多