Grouping results

89 views
Skip to first unread message

Andrew O'Brien

unread,
Sep 27, 2012, 6:10:46 PM9/27/12
to cleo-ty...@googlegroups.com
Hi, I'm spiking out Cleo to see if it's a good fit for a new feature and I'm trying to figure out how to get grouped results like the example image on http://engineering.linkedin.com/open-source/cleo-open-source-technology-behind-linkedins-typeahead-search. I've been playing around with the primer and reading a lot of the source, and I'm guessing I'm looking to populate a MultiSourceCollector...

From the look of MultiTypeahead.search, it appears that I just need to give its typeaheads appropriate names and it'll do the rest. Does that sound right, or is there more to it?

Thanks,
Andrew

Andrew O'Brien

unread,
Sep 27, 2012, 10:30:58 PM9/27/12
to cleo-ty...@googlegroups.com
Somehow I didn't see the post two below mine with almost the exact same title... So is this something that isn't really possible with Cleo, even with the Multi* classes?

Vineeth Mohan

unread,
Sep 28, 2012, 12:53:09 AM9/28/12
to cleo-ty...@googlegroups.com
Hello Jing ,

Grouping the result is one feature i would love to see in cleo.
Can you suggest an implementation path with the current stack !!!

Kindly take my request seriously and let us know what can be done to achieve this functionality without sacrificing the performance.

Thanks
           VIneeth

Jingwei

unread,
Sep 28, 2012, 4:30:40 PM9/28/12
to cleo-ty...@googlegroups.com
hi Guys,

One way for grouping typeahead search results from different kinds of typeaheads is to use MultiTypeahead. It can be constructed using a list of sub-typeaheads.

List<Typeahead<E>> subList = new ArrayList<Typeahead<E>>();
subList.add(skillTypeahead);
subList.add(companyTypeahead);
Typeahead<E> federated = new MultiTypeahead<E>("federated", subList);

Then you can call search on the federated with MultiSourceCollector or SortedCollector. This scenario is for several different sub-typeahead co-located in the same JVM instance.  Similar setup can be created for multiple sub-typeaheads on different JVM instances. Then you will have to made necessary changes according to RPC you are using.

This gives you a way to collecting different results. How to render them is another matter.

Thanks.

Jingwei

Jingwei

unread,
Sep 28, 2012, 4:32:50 PM9/28/12
to cleo-ty...@googlegroups.com
Hi,

One way for grouping typeahead search results from different kinds of typeaheads is to use MultiTypeahead. It can be constructed using a list of sub-typeaheads.

List<Typeahead<E>> subList = new ArrayList<Typeahead<E>>();
subList.add(skillTypeahead);
subList.add(companyTypeahead);
Typeahead<E> federated = new MultiTypeahead<E>("federated", subList);

Then you can call search on the federated with MultiSourceCollector or SortedCollector. This scenario is for several different sub-typeahead co-located in the same JVM instance.  Similar setup can be created for multiple sub-typeaheads on different JVM instances. Then you will have to make necessary changes according to RPC you are using.

This gives you a way to collect different results. How to render them is another matter.

Thanks.

Jingwei

Andrew O'Brien

unread,
Sep 28, 2012, 4:43:15 PM9/28/12
to cleo-ty...@googlegroups.com
Perfect—I'll give it a try.

So, MultiTypeahead both allows you to federate different sub-typeaheads and join together smaller typeaheads of the same type (as in the primer).

vineethmohan

unread,
Oct 23, 2012, 9:28:53 AM10/23/12
to cleo-ty...@googlegroups.com
Hi ,

I am still struggling to grasp the concept here.


List<Typeahead<E>> subList = new ArrayList<Typeahead<E>>();
subList.add(skillTypeahead);
subList.add(companyTypeahead);
Typeahead<E> federated = new MultiTypeahead<E>("federated", subList);

here when i created a federated multi type ahead , how will i mention that the element i want to index belongs to Company or Skill or something else ?
Also when i get the result , how will i understand from which group it is obtained ?

Thanks
           Vineeth

Andrew O'Brien

unread,
Oct 23, 2012, 10:48:19 AM10/23/12
to cleo-ty...@googlegroups.com
Hi Vineeth,

You're on the right track: you just need a MultiSourceCollector. MultiTypeahead has a version of `search` that will always return a Collector, rather than a List. See:


Cast the results of the search call like this:

MultiSearchCollector<E> results = (MultiSourceCollector<E>) federated.search(someUid, aBunchOfTerms)

If you call results.elements(), you'll just get all of the results mixed together in a single List. If you want your "skills" separated from your "companies", you can use results.sources and results.getCollector(sourceName) and collector.elements() to access the results from each typeahead on their own.

Good luck.

–Andrew

Vineeth Mohan

unread,
Oct 23, 2012, 1:44:04 PM10/23/12
to cleo-ty...@googlegroups.com
Hello Andrew ,

Thanks for your reply , but then i still haven’t grasped the concept.


files =  { "company.config" , "people.config" , "skill.config"}
for(Strinf configFile : files){
      GenericTypeahead<TypeaheadElement> gta = createTypeahead(configFile);
      indexerList.add(gta);
      searcherList.add(gta);
}
    MultiIndexer<TypeaheadElement> indexer = new MultiIndexer<TypeaheadElement>("completeList", indexerList);
    Typeahead<TypeaheadElement> searcher = new MultiTypeahead<TypeaheadElement>("Company", searcherList);


In the above code , how will i add a TypeaheadElement to the skill TypeAhead Index ?
Should i maintain a map between string and GenericTypeahead<TypeaheadElement>.
If so , what is the use of MultiIndexer ?

This is my first doubt.

The second part is how will i search between all these indexes ?

    MultiSourceCollector<TypeaheadElement> collector = new MultiSourceCollector<TypeaheadElement>();
    Collector<TypeaheadElement> result = searcher.search(1, new String[] {"i"}, collector);

Here , i don’t understand why i should pass the collector instance to the search method.
From getting the result , things are clear from your previous mail.

Thanks
            Vineeth

Andrew O'Brien

unread,
Oct 23, 2012, 3:07:50 PM10/23/12
to cleo-ty...@googlegroups.com
Hi Vineeth,

See below:


On Tuesday, October 23, 2012 1:44:06 PM UTC-4, vineethmohan wrote:

files =  { "company.config" , "people.config" , "skill.config"}
for(Strinf configFile : files){
      GenericTypeahead<TypeaheadElement> gta = createTypeahead(configFile);
      indexerList.add(gta);
      searcherList.add(gta);
}
    MultiIndexer<TypeaheadElement> indexer = new MultiIndexer<TypeaheadElement>("completeList", indexerList);
    Typeahead<TypeaheadElement> searcher = new MultiTypeahead<TypeaheadElement>("Company", searcherList);


In the above code , how will i add a TypeaheadElement to the skill TypeAhead Index ?
Should i maintain a map between string and GenericTypeahead<TypeaheadElement>.

You have two options here:

1) have a way to refer to the typeahead you created from the skills config (such as a local variable, or—probably better and as you suggested—a map) and call `index` directly on that typeahead (if that Typeahead is one of the ones that implements Indexer).
2) call `index` on the MultiIndexer with an element ID that you know will end up in the skills typeahead based on the ranges you gave to each typeahead.

I'd say 1 is probably better because it's more explicit, but I haven't fully experimented with it yet (2 could make sense if you have a component that both assigns an ID and sets up the typeahead configurations).
 
If so , what is the use of MultiIndexer ?

Take a look at MultiIndexer:


You should see see that it's basically just a List of objects that implement the Indexer interface (`index` and `flush`) that itself implements Indexer. Look at its `index` and `flush`: they pretty much just loop through the list and call those methods on each member. `index` returns true as soon as one of its child indexers successfully indexes the element (or returns false if none of them does).

So, basically it groups together multiple indexers and allows you to address them through a single `index` or `flush` call.
 
The second part is how will i search between all these indexes ?

    MultiSourceCollector<TypeaheadElement> collector = new MultiSourceCollector<TypeaheadElement>();
    Collector<TypeaheadElement> result = searcher.search(1, new String[] {"i"}, collector);

Here , i don’t understand why i should pass the collector instance to the search method.

The short answer is that all of the versions of `search` that return a Collector instead of a List require a collector to be passed in. I'm not sure if this is by design or if we're not using it as intended, but we need the collector because that's the only place where elements are still separated, so that's what we gotta do. :-/

Also, you probably don't want to pass a MultiSourceCollector in to `search`. The version of search that returns a Collector actually takes any (non-Multi) collector, clones it for each typeahead, and wraps the cloned collectors inside of a MultiSourceCollector. I'd recommend passing in a Simple or SortedCollector since it's your chance to tune parameters (like the max results per typeahead).

Hope this helps,

–Andrew

Jingwei

unread,
Oct 24, 2012, 1:24:49 AM10/24/12
to cleo-ty...@googlegroups.com
Hi Vineeth,

Andrew provided a detailed summary of multi-typeahead(s). Just an additional note here.

When you have a multi-typeahead composed of several small ones such as company and skill, you can perform indexing on individual smaller typeaheads rather than using MultiIndexer. This is because GenericTypeahead implements the Indexer interface.

Thanks.

Jingwei

Vineeth Mohan

unread,
Oct 24, 2012, 1:29:02 AM10/24/12
to cleo-ty...@googlegroups.com
Hello All ,

With Andrews help ,  i could complete my requirement.
I am planning to publish federated Cleo Premeir (With some improvements to cleo-preimer like automatic ID generation)  to open source very soon.
Thanks for all your helps.

Thanks
          Vineeth
Reply all
Reply to author
Forward
0 new messages