DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Data
  4. How to do Suggestions in RavenDB

How to do Suggestions in RavenDB

Oren Eini user avatar by
Oren Eini
·
Jul. 11, 12 · Interview
Like (0)
Save
Tweet
Share
6.00K Views

Join the DZone community and get the full member experience.

Join For Free

phil jones has posted some demo code for doing suggestions in ravendb.

        [httppost]
        public jsonresult companysuggestions(string term)
        {
            var rq = ravensession.query<company, companies_queryindex>();

            var ravenresults = rq.search(x => x.name, string.format("*{0}*", term), 
                                                      escapequeryoptions: escapequeryoptions.allowallwildcards, 
                                                      options: searchoptions.and)
                                        .take(5)
                                        .tolist();

            return json(ravenresults.select(x => new
            {
                id = x.id,
                value = x.name,
                description = string.format("({0}, {1})", x.category, x.location)
            }));
        }

and the data looks like this:

image

the companies_queryindex is a simple one, with the name field marked as analyzed.

this code works, but it isn’t ideal. in fact, it contains an major problem. it uses string .format( "*{0}*" , term), which is identical to doing a foo like ‘%’ + @term +’%’ in sql. and bad for the same reason, it means that we can’t use the index efficiently, but have to scan the entire index.

the test app also populate the database with about 30,000 documents, enough to get a handle on how thins are going, even if this is a relatively small data set. let us see how this actually behaves:

image

image image

there are a few things to note here:

  • the query time is significant . – leading wildcard queries tend to be expensive, they are essentially an o(n) query.
  • the results are… interesting. – in particular, look at the first few results, they are a match , but not what i would have expected.

a very simple change would be:

image

image image

all i did was remove the leading wildcard, and suddenly the results look at a lot nicer, if only because they are closer to what i am actually searching on. by the way, note that in the last result, we are actually finding a company whose second name starts with lua, it isn’t just a raw startswith, since we are actually working on individual tokens levels, not the entire name level. this is because we indexed the name as analyzed.

let us see how this plays out in the actual app, first, using *term*:

image

now, using term*:

image

that is somewhat better, but the results are still poor in terms of search relevance. let us try something a little bit different:

     var ravenresults = rq
        .search(x => x.name, term)
        .search(x=>x.name, term + "*", escapequeryoptions: escapequeryoptions.allowpostfixwildcard
         .take(5)
         .tolist();

here we force the search to search for the user’s actual term, as well as terms that starts with it. this means that any results that actually contains the name will stand up:

image

the most important thing about searching is to know that the problem is not that you can’t find enough information, it is that you find too much information that is not relevant.

but a better alternative all together might be using ravendb suggest feature:

[httppost]
public jsonresult companysuggestions(string term)
{
    var rq = ravensession.query<company, companies_queryindex>()
        .search(x => x.name, term)
        .take(5);

    var ravenresults = rq
        .tolist();

    if(ravenresults.count < 5)
    {
        var suggestionqueryresult = rq.suggest();

        ravenresults.addrange(ravensession.query<company, companies_queryindex>()
                                  .search(x => x.name, string.join(" ", suggestionqueryresult.suggestions))
                                  .take(5 - ravenresults.count));
    }

    return json(ravenresults.select(x => new
    {
        id = x.id,
        value = x.name,
        description = string.format("({0}, {1})", x.category, x.location)
    }));
}

which result in:

image

what we are doing here is basically query the database for exact matches. then, if we have no matches, we ask ravendb to suggest additional words, and then query for those.

here are the raw network traffic:

query:  name:<<lua>>
        time: 1 ms
        index: companies/queryindex
        results: 1 returned out of 1 total.

suggest: 
    index: companies/queryindex
    term: lua
    field=name
    time: 1 ms

query:  name:<<wlua luaz luka luau laua luoa lue luw lut lum luj lui lug luf lwa>>
        time: 3 ms
        index: companies/queryindex
        results: 4 returned out of 22 total.

as you can see, the speed difference between this and the first version is non trivial. more than that, note that it found companies with names such as “wlua”, which was also found in the first (*term*) version.

just about any searching strategy would require that you take into account the dataset, the customer requirements, the user behavior and many more. but i would start with the suggestion option before i would go to anything as brute force as *term*.

Data (computing)

Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Continuous Development: Building the Thing Right, to Build the Right Thing
  • PostgreSQL: Bulk Loading Data With Node.js and Sequelize
  • Do Not Forget About Testing!
  • AIOps Being Powered by Robotic Data Automation

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: