Algolia:如何只检索文本字段中第一次出现的搜索查询?

Algolia: how to only retrieve first occurrence of the search query in the text field?

我正在使用 Algolia 将搜索添加到我的 JAMStack 网站。但是,我的网站有一些高级内容,我希望它们可以搜索,同时对用户保持隐藏状态。
我可以通过将 body 属性添加到可搜索字段并将其从检索到的属性中删除来实现类似的功能。这样,Algolia 仍会在正文中搜索出现的查询,而不会将它们暴露给用户。
但更可取的行为是用户能够在检索到的正文中看到他搜索的内容的一两次,但不能看到优质内容的整个文本。

例如,假设我们的索引中有以下实体:

[
  {
    title: "Hello",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
  },
  {
    title: "Hi",
    body: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit"
  }
]

现在,如果我用文本 "i" 查询 algolia API,algolia 响应如下所示:

...
hits: [
  {
    title: "Hello",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
    _highlightResults: {
      body: "Lorem <em>i</em>psum dolor s<em>i</em>t amet, consectetur ad<em>i</em>p<em>i</em>sc<em>i</em>ng el<em>i</em>t, sed do e<em>i</em>usmod tempor <em>i</em>nc<em>i</em>d<em>i</em>dunt ut labore et dolore magna al<em>i</em>qua. Ut en<em>i</em>m ad m<em>i</em>n<em>i</em>m ven<em>i</em>am, qu<em>i</em>s nostrud exerc<em>i</em>tat<em>i</em>on ullamco labor<em>i</em>s n<em>i</em>s<em>i</em> ut al<em>i</em>qu<em>i</em>p ex ea commodo consequat. Du<em>i</em>s aute <em>i</em>rure dolor <em>i</em>n reprehender<em>i</em>t <em>i</em>n voluptate vel<em>i</em>t esse c<em>i</em>llum dolore eu fug<em>i</em>at nulla par<em>i</em>atur. Excepteur s<em>i</em>nt occaecat cup<em>i</em>datat non pro<em>i</em>dent, sunt <em>i</em>n culpa qu<em>i</em> off<em>i</em>c<em>i</em>a deserunt moll<em>i</em>t an<em>i</em>m <em>i</em>d est laborum."
    }
  },
  {
    title: "Hi",
    body: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit",
    _highlightResults: {
      body: "Sed ut persp<em>i</em>c<em>i</em>at<em>i</em>s unde omn<em>i</em>s <em>i</em>ste natus error s<em>i</em>t voluptatem accusant<em>i</em>um doloremque laudant<em>i</em>um, totam rem aper<em>i</em>am, eaque <em>i</em>psa quae ab <em>i</em>llo <em>i</em>nventore ver<em>i</em>tat<em>i</em>s et quas<em>i</em> arch<em>i</em>tecto beatae v<em>i</em>tae d<em>i</em>cta sunt expl<em>i</em>cabo. Nemo en<em>i</em>m <em>i</em>psam voluptatem qu<em>i</em>a voluptas s<em>i</em>t aspernatur aut od<em>i</em>t aut fug<em>i</em>t, sed qu<em>i</em>a consequuntur magn<em>i</em> dolores eos qu<em>i</em> rat<em>i</em>one voluptatem sequ<em>i</em> nesc<em>i</em>unt. Neque porro qu<em>i</em>squam est, qu<em>i</em> dolorem <em>i</em>psum qu<em>i</em>a dolor s<em>i</em>t amet, consectetur, ad<em>i</em>p<em>i</em>sc<em>i</em> vel<em>i</em>t"
  }
]

但我想要的 return 如下:

[
  {
    title: "Hello",
    _highlightResults: {
      body: "Lorem <em>i</em>psum dolor sit amet" // only the first occurance with some context
    }
  },
  {
    title: "Hi",
    _highlightResults: {
      body: "Sed ut persp<em>i</em>ciatis unde" // only the first occurance with some context
    }

  }
]

我知道可以使用代码片段完成与此类似的操作,但如果您仔细观察,body 字段也会从命中正文本身中删除,因此完整的正文永远不会发送给客户端。客户可以在内容本身未公开的情况下搜索优质内容。

如何使用 Algolia API 实现此目的?

你应该能够用 snippet 实现这样的逻辑。您不必 return 搜索它的字段。片段功能可以控制匹配时发回多少上下文。您可以将限制设置为 return 只有几个单词,以将匹配限制为单次出现。虽然它不会 100% 准确,但如果两个匹配项比给定的限制更接近,则可能会 returned(这对于实际用例来说应该不是问题)。

以下示例仅 returns name 属性进行搜索。 description设置在searchableAttributes中。这意味着查询将使用此属性进行搜索。这也意味着我们可以将它与片段功能一起使用。这里的代码段限制为 10 个字。

index.search('apple', {
  attributesToRetrieve: ['name'],
  attributesToSnippet: ['description:10'],
});

请注意,这些值是在搜索时设置的。对于客户端实现,这意味着用户将能够更改这些值。您的用例与优质内容有关,因此存在问题。要解决此问题,您必须使用带有这些参数的 API Key。您将无法在搜索时覆盖它们。