0
votes

I want to add new fields to my Lucene-based search engine site, however I want to be able to intercept queries and modify them before I pass them on to the Searcher.

For example each document has the field userid so you can search for documents authored by a particular user by their ID, e.g. foo bar userid:123 however I want to add the ability to search by username.

I'd like to add a field user:RonaldMcDonald to queries (not to documents), however I want to be able to intercept that term and replace it with an equivalent userid:123 term (my own code would be responsible for converting "RonaldMcDonald" to "123").

Here's the simple code I'm using right now:

Int32 get = (pageIndex + 1) * pageSize;

Query query;

try {

    query = _queryParser.Parse( queryText );

} catch(ParseException pex) {

    log.Add("Could not parse query.");
    throw new SearchException( "Could not parse query text.", pex );
}

log.Add("Parsed query.");

TopDocs result = _searcher.Search( query, get );

I've had a look at the Query class, but I can't see any way to retrieve, remove, or insert terms.

1
and why dont you want to index the username?Jf Beaulac
I can't index the username string because they change frequently (the users database has about 200,000 entries and roughly 10 username changes happen per day), but the index needs to remain immutable (except to add new documents).Dai

1 Answers

2
votes

You can subclass the QueryParser and override NewTermQuery.

QP qp = new QP("user", new SimpleAnalyzer());
var s = qp.Parse("user:RonaldMcDonald data:[aaa TO bbb]");

Where s is will be userid:123 data:[aaa TO bbb]

public class QP : QueryParser
{
    Dictionary<string, string> _dict = 
       new Dictionary<string, string>(new MyComparer()) {{"RonaldMcDonald","123"} };

    public QP(string field, Analyzer analyzer) : base(field, analyzer)
    {
    }

    protected override Query NewTermQuery(Term term)
    {
        if (term.Field() == "user")
        {
            //Do your username -> userid mapping
            return new TermQuery(new Term("userid", _dict[term.Text()]));
        }
        return base.NewTermQuery(term);
    }

    //Case insensitive comparer
    class MyComparer : IEqualityComparer<string>
    {
        public bool Equals(string x, string y)
        {
            return String.Compare(x, y, true, CultureInfo.InvariantCulture)==0;
        }

        public int GetHashCode(string obj)
        {
            return obj.ToLower(CultureInfo.InvariantCulture).GetHashCode();
        }
    }
}