elastic/elasticsearch-net

Cannot Query Child documents of different Type than parents.

Opened this issue · 0 comments

8.17.2:

v 8.17.2:

Dotnet 8:

Windows 11:

Description of the problem including expected versus actual behavior:
Since Replacing NEST library with new client library I have become unable to use has child queries where two differing document types are involved in any capacity, nor can I properly access the document types of inner hits. Nor can I find a way to explicitly define both the parent and child properties during the indexing request building.

Assuming the very simplistic type hierarchy below:

public class BaseDocument
{
	public string Id { get; set; }
	public required JoinField JoinField { get; set; }
}

public class Child: BaseDocument
{
	public string ChildProperty { get; set; }
}

public class Parent : BaseDocument
{
	public string ParentProperty { get; set; }	
}

Steps to reproduce:

  1. Create the Index
var createResponse = await client.Indices.CreateAsync("jointest2",
		m => m
		.Mappings(m => m

		.Routing(r => r.Required(true))
			.Properties<Parent>(
			  p => p
			  .Keyword(k => k.Id)
			  .Join(j => j.JoinField, j => j
				.Relations(r => r
				  .Add(client.Infer.RelationName<Parent>(), client.Infer.RelationName<Child>())
				)
			  )
			)
			//cannot call properties twice without replacing prior call
		//.Properties<Child>(p => p
		//  .Keyword(k => k.Id)
		//  .Text(t => t.ChildProperty)
		//  .Join(j => j.JoinField, j => j
		//	.Relations(r => r
		//	  .Add(client.Infer.RelationName<Parent>(), client.Infer.RelationName<Child>())
		//	)
		//  )

		//)
		)
	);
//however hand-rolling properties as dictionary does work if I don't specify a base indexing type

//var props = new Properties();

//props.Add<Parent>(p => p.Id, new KeywordProperty { });
//props.Add<Parent>(p => p.ParentProperty, new TextProperty { });
//props.Add<Parent>(p => p.JoinField, new JoinProperty
//{
//	Relations = new Dictionary<string, Union<string, ICollection<string>>>
//	{
//		[client.Infer.RelationName<Parent>()] = client.Infer.RelationName<Child>()
//	}
//});
//props.Add<Child>(p => p.ChildProperty, new TextProperty { });

var parent = new Parent { Id = "1", ParentProperty = "Parent", JoinField = JoinField.Root<Parent>() };
var child = new Child { Id = "2", ChildProperty = "Child", JoinField = JoinField.Link<Child>(1) };
await client.IndexAsync<Parent>(parent, index: "jointest", i => i.Routing(Routing.From(parent)));
await client.IndexAsync<Child>(child, index: "jointest", i => i.Routing(Infer.Route(child)));
  1. I am unable to define a styped searchAsync call that includes strongly typed Parent document results while that includes a strongly typed HasChild query.
    This technically works, but leaves me no way to access inner hits in a deserialized form:
var query = await client.SearchAsync<Parent>("jointest", s => s.
	Query(q => q
		.Bool(b => b.Must(m => m
			.HasChild( c => c
				.Type(client.Infer.RelationName<Child>())
                                //MatchAll can't be empty, even though we have nothing we need to configure
				.Query(cq => cq.MatchAll(new Elastic.Clients.Elasticsearch.QueryDsl.MatchAllQuery()))
				.MinChildren(1)
				.InnerHits(new Elastic.Clients.Elasticsearch.Core.Search.InnerHits { Name = "child" })
			)
		)
		)
	)
);

but I have no way to access strongly typed inner hits
var inners = query.Hits.SelectMany(h => h.InnerHits.SelectMany(i => i.Value.Hits.Hits.Select(h => h.Source)));
inners is an IEnumerable<object> and casting to Child does not work.

Expected behavior
Previously, using NEST I could issue a query like this:

var result2 = await client.SearchAsync<Parent>(
	s => s
	.Index("jointest")
	.Query(q => q.Bool(b => b.Must(q => q.HasChild<Child>(
		c => c.Query(
			c => c
			.Match(t => t.Field(f => f.ChildProperty).Query("Child"))
			).InnerHits(ih => ih.Name("child"))
		)
	)
	)));

I could also access strongly typed inner hits like so:
result2.Hits.SelectMany(h => h.InnerHits["child"].Documents<Child>());

As far as I can tell, there is no way to handle multiple types in the same query in such a fashion with the new library.

How can I work around the loss of these features?