使用Createmany动态设置类型

时间:2015-09-15 11:46:55

标签: c# oop elasticsearch

我有不同类型的文档,这些文档派生自名为Topic的基本类型。我想用:

  Client.Bulk(b => b.CreateMany(documents)

只需一次调用Bulk即可处理所有文档,如何设置每个文档的类型?

以下是一段代码:

   public IEnumerable<IBulkResponse> CreateBulkTopics(IEnumerable<Topic> topics)
    {
       var results = new List<IBulkResponse>();

       results.Add(IndexDocuments(TopicFactory.ConvertDrugsToDocuments(topics)));

       results.Add(IndexDocuments(TopicFactory.ConvertTreatmentSummariesToDocuments(topics)));

       return results; 
    }

    public IBulkResponse IndexDocuments(IEnumerable<Common.Elastic.Models.Topic> documents)
    {
        return ElasticConnector.Client.Bulk(b => b.CreateMany(documents));
    }

此时的问题是所有文件都被存储为“主题”,而不是像药物和治疗方法那样的派生类型。

2 个答案:

答案 0 :(得分:2)

Topic继承了多少种类型?它们是恒定的还是小的?那么类似的东西可以帮助你。让我们说TopicA和TopicB继承自Topic:

public IEnumerable<IBulkResponse> IndexDocuments(IEnumerable<Common.Elastic.Models.Topic> documents)
{
    yield return ElasticConnector.Client.Bulk(b => b.CreateMany(documents.OfType<TopicA>()));
    yield return ElasticConnector.Client.Bulk(b => b.CreateMany(documents.OfType<TopicB>()));
}

然后在CreateBulkTopics

results.AddRange(IndexDocuments(....

当然,只有当子类的数量很小并且可用于此代码时,这才有效。否则,您可以使用反射来实现相同的结果。示例代码有点复杂,但请告诉我您是否需要它。此外,如果子类的数量非常高,这将降低性能,因为它会将单独的请求中的每个类型发送到Bulk api。我认为客户中没有更好的评价。

编辑:这是你用反射做的方法:

class MyClass
{
    public IBulkResponse IndexDocuments<T>(IEnumerable<Topic> documents)
        where T : Topic
    {
        var derived = documents.OfType<T>();
        return ElasticConnector.Client.Bulk(b => b.CreateMany(derived));
    }

    public IEnumerable<IBulkResponse> IndexDocumentsByType(IEnumerable<Topic> documents)
    {
        var groups = documents.GroupBy(x => x.GetType());
        var method = typeof(MyClass).GetMethod(nameof(IndexDocuments)); //prior to c#6, typeof(MyClass).GetMethod("IndexDocuments")
        foreach (var group in groups)
        {
            var generic = method.MakeGenericMethod(group.Key);
            var result = generic.Invoke(this, new object[] { group });
            yield return result as IBulkResponse;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var documents = new Topic[] { new TopicA(), new TopicA(), new TopicB(), new Topic() };
        var result = new MyClass().IndexDocumentsByType(documents);
        Console.WriteLine(result.Count()); //writes 3
    }
}

答案 1 :(得分:0)

我设法使用泛型类:

  public class IndexOperations<T> where T:Topic
    {
      public ElasticConnector ElasticConnector { get; set; }

      public IndexOperations(ElasticConnector elasticConnector)
        {
            ElasticConnector = elasticConnector;
        }

      public IBulkResponse CreateMany(IEnumerable<T> t)
        {
            return ElasticConnector.Client.Bulk(b => b.CreateMany(t));
        }
    }

客户代码:

    var documents = TopicFactory.ConvertToDocuments(topics);

    SaveDrugs(documents);

    public IBulkResponse SaveDrugs(IEnumerable<Common.Elastic.Models.Topic> documents)
    {
        var indexOperations = new IndexOperations<Drug>(ElasticConnector);
        return indexOperations.CreateMany(documents.OfType<Drug>());
    }