3

I'm building a search engine using Lucene.NET / Solr.NET, and I'm wondering should search hits be returned as a dictionary or strongly typed object.

public class SearchResult
{
    public string SearchTerm { get; set; }
    public List<Dictionary<string, object>> SearchHits { get; set; }
    ...
}

// where search hit looks like this
Dictionary<string, object> searchHit = new Dictionary<string, object>
{
    { "Name", "John Doe" },
    { "Address", "Some street" },
};

vs

public class SearchResult
{
    public string SearchTerm { get; set; }
    public List<Foo> SearchHits { get; set; }
    ...
}

// where search hit looks like this
var searchHit = new SearchHit
{
    Name = "John Doe",
    Address = "Some address"
};

I will be indexing different types of objects (People, Web pages, Files, etc.). Each object has a different set of properties (people have name and address, while web pages have URLs and titles), and search hits don't have the same set of properties as original objects (WebPage class has the MainContent property, but after indexing, the search hit that represents this object will have the PreviewText property (the first 300 characters of MainContent property with stripped HTML tags).

I don't want to duplicate the code all over the place and have: IPeopleSearchService, IWebPagesSearchService, IFilesSearchService, etc. and corresponding search results: PeopleSearchResult, FileSearchResult, etc.

interface IFooService
{
    FooSearchResult Search(string text);
    void Index(Foo foo);
    ...
}

interface IBarService
{
    BarSearchResult Search(string text);
    void Index(Bar bar);
    ...
}
...

I would like to have a more generic solution, but I don't like over-complexity. It should be readable and easily understandable by junior developer.

interface ISearchService<TEntity, TSearchHit>
{
    SearchResult<TSearchHit> Search(string text);
    void Index(TEntity entity);
}

How would you design such a system? Any help would be greatly appreciated!

3
  • So, what's wrong with the generic interface you posted? It doesn't look overly complex to me.
    – svick
    Jul 22, 2013 at 18:59
  • For every TEntity I have to define TSearchHit. Does this look like overkill? Would I benefit from returning a Dictionary instead of TSearchHit?
    – šljaker
    Jul 22, 2013 at 19:04
  • Or can I just have one search service that has Dictionary<string, object> Search (string text, IEntityMappingStrategy mapper) and void Index (object entity, IEntityMappingStrategy mapper) methods, and then define / instantiate different strategies for each entity? Would that be more SOLID?
    – šljaker
    Jul 22, 2013 at 19:13

2 Answers 2

1

Basically, what you're asking is: should I make the search results statically typed? I think the answer depends on what you're going to do with them and how much do you like static typing.

Regarding what you're going to do: if you're just going to display the results to the user, or something like that that treats all the fields in the search result equally, then using a Dictionary (which is basically the same as dynamic typing) makes sense. On the other hand, if you're often going to write things like searchHist.Address (or searchHit["Address"]), then that points more to static typing.

Regarding how much you like static typing: to me, as a proponent of static typing, using dynamic typing gives you small short term advantage (e.g. you don't have to write those dozen lines declaring each TSearchHit) for significant long term disadvantages (no compiler checking for typos, no IntelliSense). This means that I think static typing is almost always worth the up-front cost. Proponents of dynamic typing would tell you otherwise, but C# is mostly statically typed language, and presumably you're using that for a reason.

1

I'm not familiar with Lucene.NET / Solr.NET but it look to me that a solution for this would be to use generic types:

public class SearchResult<TEntity>
{
    public string SearchTerm { get; set; }
    public List<Dictionary<string, TEntity>> SearchHits { get; set; }
    ...
}

interface ISearchService<TEntity>
{
    SearchResult<TEntity> Search(string text);
    void Index<TEntity>(TEntity entity);
    ...
}
1
  • 1
    The question says the type of the search result is different from the type of the normal entity.
    – svick
    Jul 22, 2013 at 19:00

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.