Re: [RavenDB] Querying nested properties in a multi-map index

830 views
Skip to first unread message

Oren Eini (Ayende Rahien)

unread,
Jul 10, 2012, 1:23:58 AM7/10/12
to rav...@googlegroups.com
Why so complex?


public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result> 
    {
        public class Result
        {
            public object[] Content { get; set; }
        }

        public SearchIndex()
        {
 
            AddMap<Page>(items => from x in items
                              select new Result { Content = new object[] { x.name, x.personAddress.streetName, x.personAddress.streetNumber } } );
 
            Index(x => x.Content, FieldIndexing.Analyzed);
        }

On Mon, Jul 9, 2012 at 11:28 PM, Nir <dj....@gmail.com> wrote:
I'm using build 960 and trying to create a multi map (other classes' properties are involved but not displayed here for the sake of simplicity), which should index nested properties within the Person class. 

    Class Person
    {
      String name;
      Address personAddress;
    } 

    Class Address
    {
      String streetName;
      int streetNumber;
    }

In the above example, I would like to index the person's name and street number;

Now, I do realize that Raven doesn't let you index nested properties but that's why I came up with the idea to create a function (by using reflection) which returns an array of the properties which I want to index and their value:

object[] GetProperties(object myObj)
{...}

My problem occurs when running this following part of code, which was taken from raven's documentation. The code doesn't actually index my data and actually returns no results when trying to query for the terms, which do reside inside the object array that GetProperties returns.

    public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result> 
    {
        public class Result
        {
            public object[] Content { get; set; }
        }

        public SearchIndex()
        {
 
            AddMap<Page>(items => from x in items
                              select new Result { Content = x.GetProperties(x) } );
 
            Index(x => x.Content, FieldIndexing.Analyzed);
        }
    }

Is dynamic assignment for the Content variable not supported ?

Help will be much appreciated !

Nir

Nir

unread,
Jul 10, 2012, 1:51:49 AM7/10/12
to rav...@googlegroups.com
Sorry, I have probably not described the situation correctly.

A solution as described above will surely work BUT my scenario is a bit different in so:

1. The class which we want to index is subject to frequent changes -> I would like to be able to generate the list of values to be indexed dynamically (that's why I created the GetProperties function).

2. What should I do in case I have a list of objects and I want to index one of the object's properties ? For example:

Class Person
    {
      String name;
      List<Address> personAddress;
    } 

    Class Address
    {
      String streetName;
      int streetNumber;
    }

Thanks again,

Nir

Oren Eini (Ayende Rahien)

unread,
Jul 10, 2012, 4:08:18 AM7/10/12
to rav...@googlegroups.com
public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result> 
    {
        public class Result
        {
            public object[] Content { get; set; }
        }

        public SearchIndex()
        {
 
            AddMap<Page>(items => from x in items
                              select new Result { Content = new object[] { x.name, x.personAddresses.Select(y=>new[]{y.streetNumber, y.streetName} } } );
 
            Index(x => x.Content, FieldIndexing.Analyzed);
Message has been deleted

Oren Eini (Ayende Rahien)

unread,
Jul 10, 2012, 7:11:50 AM7/10/12
to rav...@googlegroups.com
Sure, see.

Note that as part as the server is concerned, a dictionary and an object are one and the same.

On Tue, Jul 10, 2012 at 2:10 PM, TonyBaks <tonny.ba...@gmail.com> wrote:
1. Thanks for answering the 2nd issue! much appreciated !

2. Regarding the first issue - Is there any way of adding the the indexed values dynamically (by assigning the Content variable the return results of GetProperties) in order to avoid maintenance of the indexer ?

Thanks again,

Nir

Nir

unread,
Jul 10, 2012, 7:42:15 AM7/10/12
to rav...@googlegroups.com
Well...2 questions regarding your 2 answers:

1. If i use the following code as you suggested, I'm actually receiving an anonymous array, right ? Can that be a valid member of the Content array ?

   AddMap<Page>(items => from x in items
                                 select new Result { Content = new object[] { x.name, x.personAddresses.Select(y=>new[]{y.streetNumber, y.streetName} } } );

2. Dynamic Fields is just what I was looking for. However, Will it work if I use a reflection wrapper method to return the field name and value in runtime (I'm asking since my previous code assignment of Content = x.GetProperties(x) did not work well during runtime) ?

Thanks !

Oren Eini (Ayende Rahien)

unread,
Jul 10, 2012, 8:47:10 AM7/10/12
to rav...@googlegroups.com
1) Yes, see the discussion here:

We will "unroll" any collections during the indexing phase.
That include nested collections

2) GetProperties doesn't exists on the server.
But you can just access it like this:

Nir

unread,
Jul 10, 2012, 12:56:54 PM7/10/12
to rav...@googlegroups.com
I checked out Ayende's post regarding the index creation for all properties... It seems just perfect for what I need but does it support classes which contain Lists / Complex Objects (nested properties) ?

Thanks :)

Oren Eini (Ayende Rahien)

unread,
Jul 10, 2012, 1:38:01 PM7/10/12
to rav...@googlegroups.com
See the comment there, you do NOT want to go that way.
It is easy, but it produced really bad search results, because you are searching on everything.

Nir

unread,
Jul 11, 2012, 6:13:41 AM7/11/12
to rav...@googlegroups.com
I'm well aware of that...this is exactly the requirement for the application (searching on everything).

Getting back to my question then...is Ayende's post relevant to dynamically indexing lists / complex objects ? :)

Thanks again

Matt Warren

unread,
Jul 11, 2012, 6:51:42 AM7/11/12
to rav...@googlegroups.com
Yes, when you have an index like this:
     Map = users =>
              from user in users
              select new
              {
                  Query = AsDocument(user).Select(x => x.Value)
              };
It's taking the entire documents and in-effect indexing it as 1 big string. This allows you to search on any field within the document, but it's generally a bad idea (as pointed out above) because you lose relevancy.

Matt Warren

unread,
Jul 11, 2012, 6:59:50 AM7/11/12
to rav...@googlegroups.com
Actually I was slightly wrong, it will index each top-level property as a separate item, but if you have a nested list, it doesn't recurse thru that hierarchy.

Nir

unread,
Jul 11, 2012, 3:22:50 PM7/11/12
to rav...@googlegroups.com
Ok... Thanks :)
Reply all
Reply to author
Forward
0 new messages