我正在尝试在ES中使用动态模板,以便所有字符串字段均为多字段。我还想将某些特定的映射应用于某些字段。

采取以下示例类:

[ElasticsearchType(Name = "sample1")]
public class Sample1
{
    public string ID { get; set; }

    [String(Index = FieldIndexOption.No)]
    public string DoNotIndex { get; set; }

    public string MultiField1 { get; set; }

    public string MultiField2 { get; set; }
}

然后,我想创建动态模板,并使用以下命令将映射应用于DoNotIndex:

_client.Map<Sample1>(m => m
  .AutoMap()
  .DynamicTemplates(dt=> dt
      .DynamicTemplate("all_strings_multifields", t => t
        .MatchMappingType("string")
        .Mapping(tm => tm
            .String(mf => mf
                .Index(FieldIndexOption.Analyzed)
                .Fields(mff => mff
                    .String(s => s
                        .Name("raw")
                        .Index(FieldIndexOption.NotAnalyzed)
                    )
                )
            )
        )
    )
    )
)
.VerifySuccessfulResponse();

结果是:

{
  "test1": {
    "mappings": {
      "sample1": {
        "dynamic_templates": [
          {
            "all_strings_multifields": {
              "match_mapping_type": "string",
              "mapping": {
                "fields": {
                  "raw": {
                    "type": "string",
                    "index": "not_analyzed"
                  }
                },
                "index": "analyzed",
                "type": "string"
              }
            }
          }
        ],
        "properties": {
          "doNotIndex": {
            "type": "keyword",
            "index": false
          },
          "iD": {
            "type": "text"
          },
          "multiField1": {
            "type": "text"
          },
          "multiField2": {
            "type": "text"
          }
        }
      }
    }
  }
}

结果

您会看到DoNotIndex属性确实正确,但是multifield1multifield2不正确(它们不是多字段)。

解决方法

我知道我可以通过不做AutoMap()而不是指定每个特殊索引来“修复”此问题,但是有很多字段,而且解决方案还不够干净。

我可以使用DynamicTemplates进行AutoMap吗?

最佳答案

Dynamic templates仅适用于动态添加到映射中的字段,因此使用.AutoMap()显式映射的属性将不受动态映射的影响。

但是,存在一种使用访问者模式将约定应用于具有NEST的显式映射的方法。看来您使用的是Elasticsearch 5.0,so you should use the text and keyword mappings.

首先定义一个访客

[ElasticsearchType(Name = "sample1")]
public class Sample1
{
    public string ID { get; set; }

    [Keyword(Index = false)]
    public string DoNotIndex { get; set; }

    public string MultiField1 { get; set; }

    public string MultiField2 { get; set; }
}

public class AllStringsMultiFieldsVisitor : NoopPropertyVisitor
{
    public override void Visit(ITextProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute)
    {
        // if a custom attribute has been applied, let it take precedence
        if (propertyInfo.GetCustomAttribute<ElasticsearchPropertyAttributeBase>() == null)
        {
            type.Fields = new Properties
            {
                {
                    "raw", new KeywordProperty()
                }
            };
        }

        base.Visit(type, propertyInfo, attribute);
    }
}

然后将访问者的实例传递给.AutoMap()
client.Map<Sample1>(m => m
    .AutoMap(new AllStringsMultiFieldsVisitor())
    .DynamicTemplates(dt => dt
        .DynamicTemplate("all_strings_multifields", t => t
            .MatchMappingType("text")
            .Mapping(tm => tm
                .Text(mf => mf
                    .Index(true)
                    .Fields(mff => mff
                        .Keyword(s => s
                            .Name("raw")
                        )
                    )
                )
            )
        )
    )
);

产生

{
  "dynamic_templates": [
    {
      "all_strings_multifields": {
        "match_mapping_type": "text",
        "mapping": {
          "type": "text",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          },
          "index": true
        }
      }
    }
  ],
  "properties": {
    "iD": {
      "fields": {
        "raw": {
          "type": "keyword"
        }
      },
      "type": "text"
    },
    "doNotIndex": {
      "type": "keyword",
      "index": false
    },
    "multiField1": {
      "fields": {
        "raw": {
          "type": "keyword"
        }
      },
      "type": "text"
    },
    "multiField2": {
      "fields": {
        "raw": {
          "type": "keyword"
        }
      },
      "type": "text"
    }
  }
}

但是,我应该指出default automapping for a C# string property in NEST 5.0会将其映射为text字段,并将keyword子字段与ignore_above:256映射。 NEST 5.0 was released to nuget earlier this week

client.Map<Sample1>(m => m
    .AutoMap()
    .DynamicTemplates(dt => dt
        .DynamicTemplate("all_strings_multifields", t => t
            .MatchMappingType("text")
            .Mapping(tm => tm
                .Text(mf => mf
                    .Index(true)
                    .Fields(mff => mff
                        .Keyword(s => s
                            .Name("raw")
                        )
                    )
                )
            )
        )
    )
);

产生

{
  "dynamic_templates": [
    {
      "all_strings_multifields": {
        "match_mapping_type": "text",
        "mapping": {
          "type": "text",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          },
          "index": true
        }
      }
    }
  ],
  "properties": {
    "iD": {
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      },
      "type": "text"
    },
    "doNotIndex": {
      "type": "keyword",
      "index": false
    },
    "multiField1": {
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      },
      "type": "text"
    },
    "multiField2": {
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      },
      "type": "text"
    }
  }
}

关于elasticsearch - ElasticSearch Nest:具有DynamicTemplates的AutoMap,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41153662/

10-12 01:11