单个字段的 Elasticsearch 多个分析器

Elasticsearch multiple analyzers for a single field

我使用严格的预定义映射将不同类型的文档存储在单个索引中。它们都有一些字段(例如,"body"),但我希望在索引时对它们进行稍微不同的分析(例如,对特定文档使用不同的标记过滤器)并在搜索时以相同的方式处理。据我所知,无法为每个文档指定分析器。

我也考虑过用什么:

  1. 具有针对文档类型的不同分析子字段的对象字段,因此每个文档只有一个填充的子字段(例如,"body.mail"、"body.html")。问题是我无法搜索整个 "body" 字段,它会查看其所有子字段(不破坏现有应用程序)。
  2. 多字段的新轮回(具有带有通用分析器的 "body" 字段,并在其中自定义分析 "mail"、"html" 等)。 Hovewer,我不确定是否可以在索引时直接使用它们并在搜索时间接使用它们(例如,使用 {"mail":"smth"} 保存对象以使用特定的索引分析器,然后通过 "query":{"body":"smth"} 搜索以使用通用搜索分析器)。
  3. 要将 "body" 分成多个具有不同映射的字段,请将它们从 _all 中删除,并将 copy_to 设置为单个 body 字段。我不确定,但由于复制,它会增加大量索引开销。

我认为你可以使用多字段。使用多字段,您可以为每个子字段定义分析器(包括索引和搜索),并根据应用程序需求对相应字段进行搜索。 一般来说,索引分析器会因字段而异,搜索分析器也一样。

{
  "your_type" : {   
    "properties":{
        "body" : {
            "type" : "string",
            "index" : "analyzed",
            "index_analyzer" : "index_body_analyzer",
            "search_analyzer" : "search_body_analyzer",
            "fields" : {
                "mail" : {
                    "type" : "string",
                    "index" : "analyzed",
                    "index_analyzer" : "index_bodymail_analyzer",
                    "search_analyzer" : "search_bodymail_analyzer"
                },
                "html": {
                    "type" : "string",              
                    "index" : "analyzed",
                    "index_analyzer" : "index_bodyhtml_analyzer",
                    "search_analyzer" : "search_bodyhtml_analyzer"
                }
            }
        }
    }
}

正如我在评论中提到的,你想要的是不可能的。一句话,您的要求是:以多种方式分析相同的数据,但作为单个字段进行搜索,因为这会破坏现有的应用程序。

             -- body.html          
             -- body.email
body field ---- body.content     --- all searched as "body"
            ...
             -- body.destination
             -- body.whatever
  • 您的第一个选择是 多字段,它的确切目的是:以多种方式分析相同的数据。问题是您不能搜索 "body" 并期望 ES 搜索 body.htmlbody.email... 即使这是可能的,您也希望使用不同的分析器进行搜索。再次,不可能。此选项要求您 更改应用程序 并在 multi_matchquery_string.

  • 中搜索每个字段
  • 您的第二个选项 - reincarnation of multi-fields - 将再次无效,因为 您无法在后台引用 body 和 ES 来匹配 mailcontent

  • 第三个选项 - 使用 copy_to - 将不起作用,因为复制到另一个字段 "X" 意味着索引正在复制的数据 将使用 X的分析器,这打破了您对相同数据进行不同分析的要求。

  • 可能还有第四个选项 - "path": "just_name" from multi_fields - 乍一看应该可行。也就是说,您可以有 3 个多字段(电子邮件、内容、html),这三个字段都有一个 body 子字段。拥有 "path": "just_name" 允许您仅搜索 body,即使 body 是多个其他字段的子字段。但这是不可能的,因为这种类型的多字段 不会接受相同 body.

  • 的不同分析器

无论哪种方式,您都需要更改您的要求,因为它们不会按照您想要的方式工作。


话虽如此,我很想知道您在应用程序中使用了哪些查询。这将是一个简单的更改(是的,您需要将您的应用程序)从查询 body 字段更改为在 multi_match 中查询 body.*

我为您提供了另一种解决方案:创建多个索引,为您 body 的每个分析器创建一个索引。例如,对于 mailcontenthtml,您定义了三个索引:

PUT /multi_fields1
{
  "mappings": {
    "test": {
      "properties": {
        "body": {
          "type": "string",
          "index_analyzer": "whitespace",
          "search_analyzer": "standard"
        }
      }
    }
  }
}
PUT /multi_fields2
{
  "mappings": {
    "test": {
      "properties": {
        "body": {
          "type": "string",
          "index_analyzer": "standard",
          "search_analyzer": "standard"
        }
      }
    }
  }
}
PUT /multi_fields3
{
  "mappings": {
    "test": {
      "properties": {
        "body": {
          "type": "string",
          "index_analyzer": "keyword",
          "search_analyzer": "standard"
        }
      }
    }
  }
}

您看到它们都具有相同的 type 和相同的字段名称 - body - 但不同的 index_analyzer。然后你定义一个别名:

POST _aliases
{
  "actions": [
    {"add": {
        "index": "multi_fields1",
        "alias": "multi"}},
    {"add": {
        "index": "multi_fields2",
        "alias": "multi"}},
    {"add": {
        "index": "multi_fields3",
        "alias": "multi"}}
  ]
}

将别名命名为与当前索引相同的别名。应用程序不需要更改,它将使用相同的名称进行索引搜索,但是此名称不会指向索引,而是指向一个别名,该别名又指向您的多个指数。需要改变的是如何索引文档,因为 html 文档需要进入 multi_fields1 索引,例如 email 文档需要在 multi_fields2 索引中进行索引等等

无论您 find/choose 是什么解决方案,您的要求都需要改变,因为您想要的方式是不可能的。