medienreaktor/meilisearch

将 Meilisearch 集成到 Neos。

1.1 2024-06-18 06:45 UTC

This package is auto-updated.

Last update: 2024-09-18 07:24:08 UTC


README

将 Meilisearch 集成到 Neos。 兼容 Meilisearch 版本 1.2 至 1.8 的测试。

此包旨在简洁和最小化依赖。因此,它可能不如像 Flowpack.ElasticSearch.ContentRepositoryAdaptor 这样的包复杂和可扩展,为了实现这一点,必须从这些优秀的包中复制一些代码部分(见致谢)。

✨ 特点

  • ✅ 在 Meilisearch 中索引 Neos 内容库
  • ✅ 支持所有节点变体的内容维度
  • ✅ 命令行界面命令用于构建和刷新索引
  • ✅ 通过搜索/ Eel 辅助程序和 QueryBuilder 查询索引
  • ✅ 前端搜索表单、结果渲染和分页
  • ✅ 分面和片段高亮显示
  • ✅ 地理搜索过滤和排序
  • ✅ 向量搜索用于语义搜索/人工智能搜索
  • 🔴 目前尚不支持资产索引
  • 🔴 不支持自动完成/自动建议(目前 Meilisearch 不支持此功能)

🚀 安装

通过 composer 安装

composer require medienreaktor/meilisearch

安装 Meilisearch 的开发方式有多种。如果你使用 DDEV,有一个 Meilisearch 片段

⚙️ 配置

在你的 Settings.yaml 中配置 Meilisearch 客户端并设置端点和 API 密钥

Medienreaktor:
  Meilisearch:
    client:
      endpoint: ''
      apiKey: ''

你可以调整所有 Meilisearch 索引设置以满足你的需求(见 Meilisearch 文档)。这里配置的所有设置将直接传递给 Meilisearch。

Medienreaktor:
  Meilisearch:
    settings:
      displayedAttributes:
        - '*'
      searchableAttributes:
        - '__fulltext.text'
        - '__fulltext.h1'
        - '__fulltext.h2'
        - '__fulltext.h3'
        - '__fulltext.h4'
        - '__fulltext.h5'
        - '__fulltext.h6'
      filterableAttributes:
        - '__identifier'
        - '__dimensionsHash'
        - '__path'
        - '__parentPath'
        - '__nodeType'
        - '__nodeTypeAndSupertypes'
        - '_hidden'
        - '_hiddenBeforeDateTime'
        - '_hiddenAfterDateTime'
        - '_hiddenInIndex'
        - '_geo'
      sortableAttributes:
        - '_geo'
      rankingRules:
        - 'words'
        - 'typo'
        - 'proximity'
        - 'attribute'
        - 'sort'
        - 'exactness'
      stopWords: []
      typoTolerance:
        enabled: true
        minWordSizeForTypos:
          oneTypo: 5
          twoTypos: 9
      faceting:
        maxValuesPerFacet: 100

请勿删除,只需扩展上述 filterableAttributes,因为它们对于基本功能的工作是必需的。完成或更改配置后,请通过 CLI 命令 flow nodeindex:build 一次构建节点索引。

文档节点类型应配置为全文根(这是所有 Neos.Neos:Document 子类型的默认设置)

'Neos.Neos:Document':
  search:
    fulltext:
      isRoot: true
      enable: true

应适当配置应包含在全文搜索中的内容节点类型属性

'Neos.NodeTypes:Text':
  search:
    fulltext:
      enable: true
  properties:
    'text':
      search:
        fulltextExtractor: "${Indexing.extractHtmlTags(node.properties.text)}"

'Neos.NodeTypes:Headline':
  search:
    fulltext:
      enable: true
  properties:
    'title':
      search:
        fulltextExtractor: "${Indexing.extractHtmlTags(node.properties.title)}"

你会注意到一些属性被索引了两次,例如 _path__path_nodeType__nodeType。这是由于这些节点属性的不同 隐私

  • _*-属性是默认的 Neos 节点属性,对 Neos 是私有的(并且可能更改)
  • __*-属性是私有属性,对于 Meilisearch 集成是必需的

我们必须确保我们所需的属性始终存在,因此最好单独索引它们。

📖 与 Neos 和 Fusion 一起使用

有一个内置的内容节点类型 Medienreaktor.Meilisearch:Search 用于渲染搜索表单、结果和分页,这可能作为你项目的样板。只需将其放置在搜索页面上即可开始。

你还可以在你的 Fusion 组件中使用搜索查询、结果和分面。

prototype(Medienreaktor.Meilisearch:Search) < prototype(Neos.Neos:ContentComponent) {
    searchTerm = ${String.toString(request.arguments.search)}

    page = ${String.toInteger(request.arguments.page) || 1}
    hitsPerPage = 10

    searchQuery = ${this.searchTerm ? Search.query(site).fulltext(this.searchTerm).nodeType('Neos.Neos:Document') : null}
    searchQuery.@process {
        page = ${value.page(this.page)}
        hitsPerPage = ${value.hitsPerPage(this.hitsPerPage)}
    }

    facets = ${this.searchQuery.facets(['__nodeType', '__parentPath'])}
    totalPages = ${this.searchQuery.totalPages()}
    totalHits = ${this.searchQuery.totalHits()}
}

如果你想为某些节点属性提供分面分布或在其中进行搜索,请确保将它们添加到 Settings.yaml 中的 filterableAttributes 和/或 searchableAttributes

搜索查询构建器支持以下功能

⚡ 与 JavaScript / React / Vue 一起使用

如果您想使用JavaScript、React或Vue构建前端,您可以完全忽略上面的Neos和Fusion集成,并使用instant-meilisearch

请注意以下三件事

1. 节点上下文和维度的过滤

设置您的过滤器始终包含以下过滤器字符串:(__parentPath = "$nodePath" OR __path = "$nodePath") AND __dimensionsHash = "$dimensionsHash",其中$nodePath是上下文节点的NodePath(例如网站),$dimensionsHash是MD5散列的JSON编码上下文维度数组。

您可以在PHP中使用以下方式获取这些值

$nodePath = (string) $contextNode->findNodePath();
$dimensionsHash = md5(json_encode($contextNode->getContext()->getDimensions()));

在Fusion中,您可以通过以下方式获取这些值(假设site是您希望使用的上下文节点)

nodePath = ${site.path}
dimensionsHash = ${String.md5(Json.stringify(site.context.dimensions))}

2. 节点URI

节点的公共URI位于每个Meilisearch结果命中项的__uri属性中。

它在索引时生成,这也是为什么即使由于维度回退行为它们是冗余的,我们也会为每个节点变体创建单独的索引记录。这与Flowpack.ElasticSearch.ContentRepositoryAdaptor相反,其中只创建一个记录,并分配多个维度散列。

为了使URI生成正常工作,为您的每个站点分配一个主域名非常重要。

3. 图片URI

如果您需要在您的前端中使用图片URI,这也可以进行配置。首先,请确保在您的Settings.yaml中设置一个基本URL

Neos:
  Flow:
    http:
      baseUri: https://example.com/

然后,配置您的特定属性或所有图片属性以进行索引

Neos:
  ContentRepository:
    Search:
      defaultConfigurationPerType:
        Neos\Media\Domain\Model\ImageInterface:
          indexing: '${AssetUri.build(value, 600, 400)}'

您可以在方法参数中设置您想要的widthheight和可选的allowCroppingallowUpScalingformat值。

📍 地理搜索

Meilisearch支持基于地理位置的过滤和排序。为此功能正常工作,您的节点应提供包含lat/lng值的__geo属性。实现此功能的一种简单方法是使用代理属性

'Neos.Neos:Document':
  properties:
    latitude:
      type: 'string'
      ui:
        label: 'Latitude'
    longitude:
      type: 'string'
      ui:
        label: 'Longitude'
    __geo:
      search:
        indexing: "${{lat: node.properties.latitude, lng: node.properties.longitude}}"

搜索查询构建器支持使用geoRadius()进行过滤和使用geoPoint()进行排序(见上文)。

📐 向量搜索

您可以使用Meilisearch作为具有实验性向量搜索功能的向量存储。使用/experimental-features端点激活它,如发布说明中所述

每个文档的向量必须由您提供并在节点的_vector属性中索引。这可以通过编写一个自定义Eel助手来实现,该助手使用第三方工具(如OpenAIHugging Face)计算向量。

'Neos.Neos:Document':
  properties:
    _vector:
      search:
        indexing: "${VectorIndexing.computeByNode(node)}"

搜索查询构建器支持通过向量进行查询。根据您的用例,必须在搜索短语中重新计算向量,例如

prototype(Medienreaktor.Meilisearch:Search) < prototype(Neos.Neos:ContentComponent) {
    searchTerm = ${String.toString(request.arguments.search)}
    searchVector = ${VectorIndexing.computeByString(this.searchTerm)}

    vectorSearchQuery = ${this.searchVector ? Search.query(site).vector(this.searchVector) : null}

    searchResults = ${this.vectorSearchQuery.execute()}
}

要显示与当前文档类似的文档(例如用于维基、知识库或新闻室),请使用当前文档的向量作为搜索向量。

👩‍💻 致谢

此软件包受到以下软件包的极大启发,并复制了一些较小的代码部分:

所有荣誉都归功于这些软件包的原始作者。