4

Given the following POCOs:

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

public class Cat
{
    public string Name { get; set; }
    public bool Enabled { get; set; }
}

I would like to perform a query that returns ALL Dogs and only Cats that are Enabled.

The elastic docs provide the following example but not any detail on how to use a Bool with query or filter context to search for specific field values across multiple types:

.Search<object>(s => s
    .Size(100)
    .Type(Types.Type(typeof(Dog), typeof(Cat)))                
    .Query(...)

How do I perform my query?, Thanks in advance

1
  • Is there any way to apply filtering on specific type alone? Commented Nov 17, 2016 at 11:23

1 Answer 1

2

We can query on the metadata _type field and combine this with queries on other fields. Here's an example. We'll create 100 cats and 100 dogs, setting each even cat to be disabled

void Main()
{
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    var defaultIndex = "pets";
    var connectionSettings = new ConnectionSettings(pool)
            .DefaultIndex(defaultIndex);

    var client = new ElasticClient(connectionSettings);

    if (client.IndexExists(defaultIndex).Exists)
        client.DeleteIndex(defaultIndex);

    client.CreateIndex(defaultIndex, ci => ci
        .Mappings(m => m
            .Map<Dog>(d => d.AutoMap())
            .Map<Cat>(c => c.AutoMap())
        )
    );

    var dogs = Enumerable.Range(1, 100).Select(i => new Dog
    {
        Name = $"Dog {i}"
    });

    client.IndexMany(dogs);

    var cats = Enumerable.Range(1, 100).Select(i => new Cat
    {
        Name = $"Cat {i}",
        Enabled = i % 2 == 0 ? false : true
    });

    client.IndexMany(cats);
    client.Refresh(defaultIndex);

    client.Search<object>(s => s
        .Size(100)
        .SearchType(SearchType.Count)
        .Type(Types.Type(typeof(Dog), typeof(Cat)))
        .Query(q => 
            (+q.Term("_type", "cat") && +q.Term("enabled", true)) ||
            +q.Term("_type", "dog")
        )
    );
}

The search query takes advantage of operator overloading; the unary + operator will mean that the query will be wrapped in a bool query filter and similarly, && will wrap into a bool query must (or filter in this case as we also use the + unary operator to make it a filter), and || will wrap into a bool query should. The resulting executed query looks like

{
  "size": 100,
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "filter": [
              {
                "term": {
                  "_type": {
                    "value": "cat"
                  }
                }
              },
              {
                "term": {
                  "enabled": {
                    "value": true
                  }
                }
              }
            ]
          }
        },
        {
          "bool": {
            "filter": [
              {
                "term": {
                  "_type": {
                    "value": "dog"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

which yields

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 150,
    "max_score" : 0.0,
    "hits" : [ ]
  }
}

This is only a count, but if you were to look at the documents, it would be all dogs and only cats that are enabled

Sign up to request clarification or add additional context in comments.

1 Comment

Is there any way to apply filtering on specific type alone?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.