How to search on multiple fields with boost weights? - elasticsearch

At the moment I'm using this:
response = await ElasticClient.SearchAsync<Product>(s => s
.From(skip)
.Size(productSearch.ItemsPerPage)
.Index(productSearch.Company + PartOfIndexName + productSearch.Country)
.Query(q => q
.QueryString(c => c
.Fields(f => f
.Field(p => p.IdPart1, 4.0)
.Field(p => p.Title, 4.0)
.Field(p => p.BrandName, 3.0)
.Field(p => p.Description, 2.0)
)
.Query("*" + productSearch.Query + "*")
)
)
);
But this doesn't work. No results get returned. But I get a valid response (debug information: "Valid NEST response built from a successful low level call on POST"). Does anyone have any idea what I'm doing wrong? It's been days now and I still can't figure it out.
When I query it via the Elasticsearch REST API like this:
POST http://localhost:9200/company_products_country/_search
body:
{
"size": 10,
"query": {
"match": {
"title": "something"
}
}
}
Then it works and I get results. But if I search the description field for something like: "787920/1", then I get no results. The description field is a 500 char text field.
I index the documents like this:
ElasticClient.Index(product, idx => idx.Index(indexName));

Related

Sorting Innerhits results using Nest

I'm having trouble figuring out the correct usage of .Sort() for inner hits. If I have a document structure like:
{
"id": "whatever",
"sales": [
{
"startsOn": "2022-05-01T00:00:00"
"endsOn": "2022-05-31T23:59:59"
"discountPercent": 0.10
},
{
"startsOn": "2022-06-01T00:00:00"
"endsOn": "2022-06-31T23:59:59"
"discountPercent": 0.15
}
]
}
I'm trying to order the innerResults by startsOn descending and my InnerHits code looks something like:
client.SearchAsync<Product>(x =>
x.Query(q =>
q.Nested(n =>
n.Path(p => p.sales)
.Query(q => q.DateRange( /* misc date range*/))
.InnerHits(ih => ih.Name("sorted_Sales")))));
I tried adding .Sort() after the .Name() but I get a
FieldSortDescriptor does not contain a definition for sales and no accessible exensiont method yada yada
Below will sort inner hits with descending order using startsOn field.
.InnerHits(ih => ih
.Name("sorted_Sales")
.Sort(s => s
.Descending(d => d.sales.FirstOrDefault()!.startsOn))))))

Change ElasticSearch track_total_hits in NEST

I was running thought examples of ElasticSearch, and read this link that says that there is a default set at 10,000, which also can be changed on the search calls, like on this example
GET twitter/_search
{
"track_total_hits": 100,
"query": {
"match" : {
"message" : "Elasticsearch"
}
}
}
The problem is, I'm trying to do the same on NEST, but I don't manage to replicate it. The only thing similar that I found, only accept a Boolean value and not a number. It is possible to change the total through NEST?
Here is the code that I tried:
var results = elasticClient.Search<MyClass>(s => s
.Query(q => q.QueryString(q2 => q2.Query(readLine)
.Fields(f => f.Field(p => p.MyField)))).TrackTotalHits(true));
As stated by #russcam here at the moment you can do it via casting ISearchRequest to IRequest<SearchRequestParameters>:
var client = new ElasticClient();
var searchResponse = client.Search<Document>(s =>
{
IRequest<SearchRequestParameters> request = s;
request.RequestParameters.SetQueryString("track_total_hits", 1000);
return s;
});
It will apply it as querystring parameter

Setting the Elasticsearch routing_partition_size using NEST

I'm using NEST to create an index in Elasticsearch 5.5. I need to update the index.routing_partition_size setting on index creation but don't see that setting in the in CreateIndexDescriptor object. How can I specify what this value is in NEST?
My settings currently looks like this:
return createIndexSelector
//add analyzers and tokenizers
.Settings(s => s
.NumberOfReplicas(2)
.NumberOfShards(40)
.Setting("refresh_interval", 10)
.Analysis(a => a
.Analyzers(az => az
.Custom("str_search_analyzer", c1 => GetCustomSearchAnalyzer())
.Custom("str_index_analyzer", c2 => GetCustomNgramAnalyzer()))
.Tokenizers(tz => tz
.NGram("autocomplete_ngram_tokenizer", ng => GetCustomAutoCompleteTokenizer()))))
//add mappings for invoice and contact doc types
.Mappings(m => m
.Map<DocType>(mDocType => mDocType .Properties(DocType.AddAllMappings)));
Assuming you are using NEST 5.x, it's under IndexSettingsDescriptor
var createIndexResponse = await client.CreateIndexAsync("index", c => c
.Settings(s => s.RoutingPartitionSize(10)));
Which produces the following request
{
"settings": {
"index.routing_partition_size": 10
}
}
Hope that helps.

Adding FunctionScore/FieldValueFactor to a MultiMatch query

We've got a pretty basic query we're using to allow users to provide a query text, and then it boosts matches on different fields. Now we want to add another boost based on votes, but not sure where to nest the FunctionScore in.
Our original query is:
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.MultiMatch(mm => mm
.Fields(f => f
.Field("name^5")
.Field("hobbies^2")
)
.Query(queryText)
)
)
);
If I try to nest in FunctionScore around the MultiMatch, it basically ignores the query/fields, and just returns everything in the index:
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.FunctionScore(fs => fs
.Query(q2 => q2
.MultiMatch(mm => mm
.Fields(f => f
.Field("name^5")
.Field("hobbies^2")
)
.Query(queryText)
)
)
)
)
);
My expectation is that since I'm not providing a FunctionScore or any Functions, this should basically do the exact same thing as above. Then, just adding in FunctionScore will provide boosts on the results based on the functions I give it (in my case, boosting based on the votes field just FieldValueFactor).
The documentation around this is a little fuzzy, particularly with certain combinations, like MultiMatch, FunctionScore, and query text. I did find this answer, but it doesn't cover when including query text.
I'm pretty sure it boils down to my still foggy understanding of how Elastic queries work, but I'm just not finding much to cover the (what I would think is a pretty common) scenario of:
A user entering a query
Boosting matches of that query with certain fields
Boosting all results based on the value of a numeric field
Your function_score query is correct, but the reason that you are not seeing the results that you expect is because of a feature in NEST called conditionless queries. In the case of a function_score query, it is considered conditionless when there are no functions, omitting the query from the serialized form sent in the request.
The easiest way to see this is with a small example
private static void Main()
{
var defaultIndex = "my-index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool, new InMemoryConnection())
.DefaultIndex(defaultIndex)
.DisableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails =>
{
if (callDetails.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var client = new ElasticClient(settings);
var queryText = "query text";
var results = client.Search<dynamic>(s => s
.Query(q => q
.FunctionScore(fs => fs
.Query(q2 => q2
.MultiMatch(mm => mm
.Fields(f => f
.Field("name^5")
.Field("hobbies^2")
)
.Query(queryText)
)
)
)
)
);
}
which emits the following request
POST http://localhost:9200/my-index/object/_search?pretty=true&typed_keys=true
{}
You can disable the conditionless feature by marking a query as Verbatim
var results = client.Search<dynamic>(s => s
.Query(q => q
.FunctionScore(fs => fs
.Verbatim() // <-- send the query *exactly as is*
.Query(q2 => q2
.MultiMatch(mm => mm
.Fields(f => f
.Field("name^5")
.Field("hobbies^2")
)
.Query(queryText)
)
)
)
)
);
This now sends the query
POST http://localhost:9200/my-index/object/_search?pretty=true&typed_keys=true
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "query text",
"fields": [
"name^5",
"hobbies^2"
]
}
}
}
}
}

Google big query "required parameter missing" with ruby gem

I'm using Google's ruby api client to talk to big query and I have it all set up and working, except for queries where I'm getting this error:
{"error"=>
{"errors"=>
[{"reason"=>"required",
"domain"=>"global",
"message"=>"Required parameter is missing"}],
"code"=>400,
"message"=>"Required parameter is missing"}}
Here is what I'm calling:
bq = client.discovered_api("bigquery", "v2")
resp = client.execute(
bq.jobs.query,
{ "projectId" => "1234",
"query" => "SELECT count(*) FROM [api_logs.api_logs_week_28__Jul_2012] where timestamp >= 1341817200 and timestamp <= 1341903599"
}
)
The frustrating part is on the query api docs, these same exact parameters work just fine. Any ideas?
First- - I don't know ruby, but I do know bigquery, so I've taken a look at the ruby google drive example and tried to adapt it:
result = client.execute(
:api_method => bq.jobs.query,
:body_object => { "query" => "SELECT 17" },
:parameters => { "projectId => "1234" })
Essentially the projectId needs to be a parameter, and the query needs to be in the post data.

Resources