简体   繁体   中英

lucene.net search multiple fields with one value AND other field with another value

I have a Lucene doc with various fields; Name, BriefData, FullData, ParentIDs (comma delimted string), ProductType, Experience.

I have a search form with a text box, drop down of parents, dropdown of product types, dropdown of experience.

If I search from the text box I get the results I should. If I search from any of dropdowns (or all of them) I get the results I want. If I use the dropdowns AND the textbox I get all results as a search of textbox OR dropdowns. What I want is textbox AND dropdowns.

So, my search builds something like so:

        if (string.IsNullOrWhiteSpace(searchTerm))
        {
            searchTerm = "";
            if (!string.IsNullOrWhiteSpace(Request.QueryString["textbox"]))
            {
                string tester = Request.QueryString["query"];
                searchTerm += tester;
            }
            if (!string.IsNullOrWhiteSpace(Request.QueryString["parent"]))
            {
                searchTerm += searchTerm.Length > 0 ? " " : "";
                searchTerm += "+ParentIDs:" + Request.QueryString["parent"];
            }
            if (!string.IsNullOrWhiteSpace(Request.QueryString["product"]))
            {
                ProductTypes pt = db.ProductTypes.Find(int.Parse(Request.QueryString["product"]));
                if (pt != null) {
                    searchTerm += searchTerm.Length > 0 ? " " : "";
                    searchTerm += "+ProductType:" + pt.TypeName;
                }
            }
            if (!string.IsNullOrWhiteSpace(Request.QueryString["experience"]))
            {
                searchTerm += searchTerm.Length > 0 ? " " : "";
                searchTerm += "+Experience:" + Request.QueryString["experience"];
            }
        }
        if (!Directory.Exists(Helper.LuceneSearch._luceneDir))
            Directory.CreateDirectory(Helper.LuceneSearch._luceneDir);

        _searchResults = string.IsNullOrEmpty(searchField)
                            ? Helper.LuceneSearch.Search(searchTerm).Distinct()
                            : Helper.LuceneSearch.Search(searchTerm, searchField).Distinct();

        return View(_searchResults.Distinct());

If I am searching just textbox and dropdown parent I get a searchterm of "north +ParentIDs:62"

What I want is the search to ONLY return results with a parent of 62 AND (Name OR BriefData OR FullData of "north").

I have tried creating a searchTerm of "+(Name:north BriefData:north FullData:north) +ParentIDs:62" and "Name:north BriefData:north FullData:north +ParentIDs:62". The first returns no results and the second returns the same as just searching +ParentIDs:62.

I think the logic behind this is pretty simple. However, I have no idea what it is that I need to write in code.

Please help. :)

Thanks to JF Beaulac giving me cause to look at the Lucene.Net code I had included (Helper.LuceneSearch.Search(searchTerm).Distinct()) I rewrote my search to essentially not bother using that but instead to somewhat duplicate it.

I did this by using the MultiFieldQueryParser for the, oddly enough, multi-field search I wanted. I then used the TermQuery for single field queries. These were all added to a BooleanQuery and my search was executed against said BooleanQuery.

var hits_limit = 1000;
var analyzer = new StandardAnalyzer(Version.LUCENE_29);
BooleanQuery bq = new BooleanQuery();
if (string.IsNullOrWhiteSpace(searchTerm))
{
    searchTerm = "";
    if (!string.IsNullOrWhiteSpace(Request.QueryString["textbox"]))
    {
        string tester = Request.QueryString["textbox"];
        var parser = new MultiFieldQueryParser(Version.LUCENE_29, new[] { "Name", "BriefData", "FullData" }, analyzer);
        var query = Helper.LuceneSearch.parseQuery(tester.Replace("*", "").Replace("?", ""), parser);
        bq.Add(query, BooleanClause.Occur.MUST);
    }
    if (!string.IsNullOrWhiteSpace(Request.QueryString["parent"]))
    {
        bq.Add(new TermQuery(new Term("ParentIDs", Request.QueryString["parent"])), BooleanClause.Occur.MUST);
    }
    if (!string.IsNullOrWhiteSpace(Request.QueryString["product"]))
    {
        ProductTypes pt = db.ProductTypes.Find(int.Parse(Request.QueryString["product"]));
        if (pt != null) {
            bq.Add(new TermQuery(new Term("ProductType", pt.TypeName)), BooleanClause.Occur.MUST);
        }
    }
    if (!string.IsNullOrWhiteSpace(Request.QueryString["experience"]))
    {
        bq.Add(new TermQuery(new Term("Experience", Request.QueryString["experience"])), BooleanClause.Occur.MUST);
    }
}
if (!System.IO.Directory.Exists(Helper.LuceneSearch._luceneDir))
    System.IO.Directory.CreateDirectory(Helper.LuceneSearch._luceneDir);

var searcher = new IndexSearcher(Helper.LuceneSearch._directory, false);
var hits = searcher.Search(bq, null, hits_limit, Sort.RELEVANCE).ScoreDocs;
var results = Helper.LuceneSearch._mapLuceneToDataList(hits, searcher).Distinct();
analyzer.Close();
searcher.Close();
searcher.Dispose(); 

return View(results);

It should be noted that to get the product and experience fields to work I had to set them to "Field.Index.NOT_ANALYZED" when adding them to the index. I'm guessing this was because they would only ever have a single value per document. The other searched fields are "Field.Index.ANALYZED".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM