使用 annotated-text 字段

编辑

annotated-text 字段会根据更常见的 text 字段对文本内容进行分词(参见下面的“限制”),但也会将任何标记的注释标记直接注入搜索索引。

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "my_field": {
        "type": "annotated_text"
      }
    }
  }
}

这种映射允许将标记的文本(例如维基百科文章)索引为文本和结构化标记。注释使用类似 Markdown 的语法,使用一个或多个以 & 符号分隔的值的 URL 编码。

我们可以使用 "_analyze" API 来测试示例注释如何在搜索索引中存储为标记。

GET my-index-000001/_analyze
{
  "field": "my_field",
  "text":"Investors in [Apple](Apple+Inc.) rejoiced."
}

响应

{
  "tokens": [
    {
      "token": "investors",
      "start_offset": 0,
      "end_offset": 9,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "in",
      "start_offset": 10,
      "end_offset": 12,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "Apple Inc.", 
      "start_offset": 13,
      "end_offset": 18,
      "type": "annotation",
      "position": 2
    },
    {
      "token": "apple",
      "start_offset": 13,
      "end_offset": 18,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "rejoiced",
      "start_offset": 19,
      "end_offset": 27,
      "type": "<ALPHANUM>",
      "position": 3
    }
  ]
}

请注意,整个注释标记 Apple Inc. 在标记流中保持不变,作为一个单独的标记,并且与它注释的文本标记 (apple) 处于相同的位置(位置 2)。

我们现在可以使用常规的 term 查询来搜索注释,这些查询不会对提供的搜索值进行分词。注释是一种更精确的匹配方式,从这个示例中可以看出,搜索 Beck 将不会匹配 Jeff Beck

# Example documents
PUT my-index-000001/_doc/1
{
  "my_field": "[Beck](Beck) announced a new tour"
}

PUT my-index-000001/_doc/2
{
  "my_field": "[Jeff Beck](Jeff+Beck&Guitarist) plays a strat"
}

# Example search
GET my-index-000001/_search
{
  "query": {
    "term": {
        "my_field": "Beck" 
    }
  }
}

除了将纯文本分词为单个单词(例如 beck)之外,我们还在标记流中与 beck 相同的位置注入单个标记值 Beck

请注意,注释可以在相同的位置注入多个标记 - 在这里,我们同时注入了非常特定的值 Jeff Beck 和更广泛的术语 Guitarist。这使得更广泛的位置查询成为可能,例如查找 Guitarist 附近 strat 的提及。

使用这些精心定义的注释标记进行搜索的一个好处是,查询 Beck 不会匹配包含标记 jeffbeckJeff Beck 的文档 2。

在注释值中使用 = 符号(例如 [Prince](person=Prince))会导致文档被拒绝并出现解析错误。将来,我们希望能够使用等号,因此今天将主动拒绝包含等号的文档。

合成 _source

编辑

合成 _source 仅对 TSDB 索引(索引的 index.mode 设置为 time_series)普遍可用。对于其他索引,合成 _source 处于技术预览阶段。技术预览中的功能可能会在将来的版本中更改或删除。Elastic 将致力于修复任何问题,但技术预览中的功能不受官方 GA 功能的支持 SLA 的约束。

如果使用子 keyword 字段,则值的排序方式与 keyword 字段值的排序方式相同。默认情况下,这意味着按排序并删除重复项。所以

PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text": {
        "type": "annotated_text",
        "fields": {
          "raw": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
PUT idx/_doc/1
{
  "text": [
    "the quick brown fox",
    "the quick brown fox",
    "jumped over the lazy dog"
  ]
}

将变成

{
  "text": [
    "jumped over the lazy dog",
    "the quick brown fox"
  ]
}

重新排序文本字段可能会影响 短语跨度 查询。有关更多详细信息,请参阅有关 position_increment_gap 的讨论。您可以通过确保短语查询上的 slop 参数低于 position_increment_gap 来避免这种情况。这是默认设置。

如果 annotated_text 字段将 store 设置为 true,则会保留顺序和重复项。

PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text": { "type": "annotated_text", "store": true }
    }
  }
}
PUT idx/_doc/1
{
  "text": [
    "the quick brown fox",
    "the quick brown fox",
    "jumped over the lazy dog"
  ]
}

将变成

{
  "text": [
    "the quick brown fox",
    "the quick brown fox",
    "jumped over the lazy dog"
  ]
}