简体   繁体   中英

Using NEST on ElasticSearch - How do i use a partially populated object as a search criteria

So I have successfully created my index of "Package" objects and a straight forward text query is working perfectly.

I'd love to know if / how i can use a partially populated object (of type "Package") as the criteria for my search?

Packages looks something like:

var packages =  new List<Package> {
            new Package {
                Name = "Maverick",
                TargetBusiness = new Business {
                    Industry = "Retail",
                    BusinessType = BusinessType.Product,
                    LocationType = LocationType.Store
                },
                Description = "Standard package for retail shops"
            },
            new Package {
                Name = "Goose",
                TargetBusiness = new Business {
                    Industry = "Retail",
                    BusinessType = BusinessType.Product,
                    LocationType = LocationType.Online
                },
                Description = "Standard package for ecommerce shops"
            },
            new Package {
                Name = "Viper",
                TargetBusiness = new Business {
                    Industry = "Advertising",
                    BusinessType = BusinessType.Service,
                    LocationType = LocationType.Office
                },
                Description = "Standard package test retail"
            }
        }

query currently looks something like:

var result = client.Search<Package>(x => x.Query(q => q.QueryString(qs => qs.Query("q=retail"))));

But id like to have something like:

var result = client.Search<Package>(x => x.Query(q => q.Object(new Package{...etc ...})));

I hope I'm making sense :D Thanks in advance

var result = client.Search<Package>(x => x.Query(q => q.Object(new Package{...etc ...})));

Can never work because Nest cannot infer what type of query to use for each property on your object, (ie term, prefix, wildcard, query_string, etc etc etc).

In your example q=retail only works because elasticsearch will break the query up into q OR retail . You can target fields using regular lucene syntax ie targetBusiness.industry:retail .

In elasticsearch if your querystring is not bound to a field it will by default search in the _all field which will have all the terms for all the properties of an object. Which is why if you really have a lot of data turning off _all support is usually a really good idea.

Nest doesn't currently have such a functionality where it can take a partially filled object and translate it into an elasticsearch query_string query.

Say if this is your query:

client.Search<Package>(s=>s
    .From(0)
    .Size(10)
    .Filter(f=>
        f.Term(p=>p.TargetBusiness.Industry, "Advertising")
        && f.Exists(p=>p.Name)
    )
    .Query(q=>
       q.QueryString(qs=>qs
           .Query("ecommerce")
           .Operator(Operator.and)
       )
    )
)

In the above example you'll have to create your own method that gives all the terms to search for in the query string query based on your package.

ie

public string MyPackageQueryString(Package package) 
{
    var myTerms = List<string>();
    myTerms.Add(package.Name);
    if (package.TargetBusiness != null)
    {
        myTerms.Add(package.Industry)
        ....
    }
    ...
    return string.Join(" ", myTerms.Where(t=>!string.IsNullOrWhiteSpace(t)));
}

and then

client.Search<Package>(s=>s
    .From(0)
    .Size(10)
    .Filter(f=>
        f.Term(p=>p.TargetBusiness.Industry, "Advertising")
        && f.Exists(p=>p.Name)
    )
    .Query(q=>
       q.QueryString(qs=>qs
           .Query(this.MyPackageQueryString(package))
           .Operator(Operator.or)
       )
    )
)

That really helped put me on the right track - in the end that looked like a sort of cross search: Searching every field with every other field which i didn't want.

Ended up (possible incorrectly) going with:

return _searchClient.Search<Package>(s => s.Query(q => 
        q.Term("industry", criteriaPackage.TargetBusiness.Industry.ToLower()) ||
        q.Term("description", criteriaPackage.TargetBusiness.Description.ToLower()) ||
        q.Term("businessType",((int)criteriaPackage.TargetBusiness.BusinessType).ToString()) ||
        q.Term("locationType", ((int)criteriaPackage.TargetBusiness.LocationType).ToString()) ||
        q.Term("marketSegment", criteriaPackage.TargetBusiness.MarketSegment.ToLower()) ||
        q.Term("offer", criteriaPackage.TargetBusiness.Offer.ToLower()))
      ).Documents;

Which after a few unit tests seemed to be producing the results i was wanting.

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