Elasticsearch.Nest 教程系列 4-7 映射:Multi fields | 多字段映射


在 ES 中,多字段映射是很有用的,如:

  • 一个 string 类型的属性会被推断为 ES 的 包含 keyword 子字段的 text 数据类型,其中:
    • text 数据类型适用于全文搜索。
    • keyword 适用于结构搜索、排序以及聚合。
  • 另外多字段映射适用于不同的分析器,以满足不同的全文本搜索需求。

假设有如下模型类:

public class Person
{
    public string Name { get; set; }
}

string 类型的默认映射

使用 AutoMappin的情况下,在推断 string 类型的映射时,会自动推断出一个包含 keyword 子字段的的多字段文本数据类型:

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Person>(m => m
        .AutoMap()
    )
);

结果如下:

{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

使用 text 和 keyword 数据类型来进行全文搜索,排序和聚合:

var searchResponse = _client.Search<Person>(s => s
    .Query(q => q
        .Match(m => m
            .Field(f => f.Name)
            .Query("Russ")
        )
    )
    .Sort(ss => ss
        .Descending(f => f.Name.Suffix("keyword")) //在 Name 上使用 keyword
    )
    .Aggregations(a => a
        .Terms("peoples_names", t => t
            .Field(f => f.Name.Suffix("keyword"))
        )
    )
);

结果如下:

{
  "query": {
    "match": {
      "name": {
        "query": "Russ"
      }
    }
  },
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      }
    }
  ],
  "aggs": {
    "peoples_names": {
      "terms": {
        "field": "name.keyword"
      }
    }
  }
}
  • 多字段不会更改 ES 中原始的 _source 字段;
  • 仅影响字段的索引方式。
  • 通过使用 Put Mapping API,可以将新的多字段添加到现有字段中。

创建多字段

通过在创建时候,使用 Map 方法 中的 .Fields() 方法可以创建多字段:

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Person>(m => m
        .Properties(p => p
            .Text(t => t
                .Name(n => n.Name)
                .Fields(ff => ff
                    .Text(tt => tt
                        .Name("stop")  //在这个子字段上使用 停用词过滤器
                        .Analyzer("stop")
                    )
                    .Text(tt => tt
                        .Name("shingles")
                        .Analyzer("name_shingles")  //使用自定义的名为 named_shingles 过滤器
                    )
                    .Keyword(k => k
                        .Name("keyword") 
                        .IgnoreAbove(256)
                    )
                )
            )
        )
    )
);

mapping 信息如下:

{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "stop": {
            "type": "text",
            "analyzer": "stop"
          },
          "shingles": {
            "type": "text",
            "analyzer": "name_shingles"
          },
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}