How to search based on field in azure search? - c#

i am using a azure search, and i have a console app with the code as below, which is working fine.
DocumentSearchResult<Hotel> results;
Console.WriteLine("Search started\n");
results = indexClient.Documents.Search<Hotel>("smart", new SearchParameters { Top=5 });
WriteDocuments(results);
currently its searching a text with word "smart". this is straight forword, what i need is i have several fields in the table, i want to search based on the feild .
for example let i have two fields
1)Title
2)SoldDate
I have to write code for finding items which has title 'john' and which has a sold date < current date.
what should i do to achieve this?

You can achieve what you want with search and a filter:
// Approach #1
string currentDate = DateTime.UtcNow.ToString("O");
var parameters = new SearchParameters()
{
Filter = "soldDate lt " + currentDate,
Top = 5
}
results = indexClient.Documents.Search<Hotel>("john", parameters);
This will filter the documents to only those with a soldDate before currentDate, and then searches the filtered documents such that documents match if any of the searchable fields contain "john". You can narrow this down to just the title field like this:
// Approach #2
string currentDate = DateTime.UtcNow.ToString("O");
var parameters = new SearchParameters()
{
Filter = "soldDate lt " + currentDate,
SearchFields = new[] { "title" },
Top = 5
}
results = indexClient.Documents.Search<Hotel>("john", parameters);
Or like this:
// Approach #3
string currentDate = DateTime.UtcNow.ToString("O");
var parameters = new SearchParameters()
{
Filter = "soldDate lt " + currentDate,
QueryType = QueryType.Full,
Top = 5
}
results = indexClient.Documents.Search<Hotel>("title:john", parameters);
Which way you use depends on whether you want all search terms to be limited to a specific set of fields (Approach #2), or if you want specific terms to match specific fields (Approach #3).
The reference for SearchParameters is on learn.microsoft.com.

Related

How set OrderBy on GroupedEnumerable

My result set is not sorting. How do I set up OrderBy for type System.Linq.GroupedEnumerable
I've converted an application from Core 1.1 to 2.2. Everything ported over fine except one piece of logic that:
1) takes a response from a service call maps it to a GroupedEnumerable
2) takes the grouped set and passes it to a function that maps it to an object of type System.Linq.Enumerable.SelectEnumerableIterator.
The resulting object is properly populated but not sorted. I have tried the order by in the function parameter call and as a separate process afterwards.
//response = {myService.myClient.SearchNominationsResponse}
//groupedSet = {System.Linq.GroupedEnumerable<ServiceClients.myClient.NominationObject, long>}
//result = {System.Linq.Enumerable.SelectEnumerableIterator<System.Linq.IGrouping<long, ServiceClients.myClient.NominationObject>, app.ViewModels.EvaluationSummary>}
public IEnumerable<EvaluationSummary> GetEvaluationSummaries(string sortBy, string sortOrder, Filter filter = null)
{
var request = Mapper.MapSearchNominationRequest(filter);
request.IsDetailed = false;
var response = myService.SearchNominationsAsync(request).GetAwaiter().GetResult();
var groupedSet = response.mySet.GroupBy(n => n.SetId);
// I get a proper result but it is not sorted
var result = groupedSet.Select(
g => Mapper.MapEvaluationSummary(
g.OrderBy(g2 => sortBy + " " + sortOrder)
.Last()));
// Still not sorting
result = result.OrderBy(r => sortBy + sortOrder);
return result;
}
public EvaluationSummary MapEvaluationSummary(SetObject setIn)
{
var eval = new EvaluationSummary
{
setDate = setIn.Date,
setId = setIn.Id,
setTypeId = setIn.TypeId,
setTypeDescription = setIn.TypeDescription,
setStatusId = setIn.StatusId,
setStatusDescription = setIn.StatusDescription,
setBy = setIn.Manager,
setEmployee = setIn.employee
};
}
So in my view I have columns that list Date, Id, setEmployee. I can click on these values to issue a sort pattern and I can see that the sortBy and sortOrder variables are being passed in with proper values but the sorting is not happening.
I expect 'William' to appear before 'Bill' and then Bill to appear before 'William' when toggling the employee column header in my view.
Based off of the previous answers, I'm still not sure if I can substitute a property name in the LINQ with a variable. To fix my problem and move on I've implemented JS logic to sort my table headers. We had a custom JS that we use to format tables in our apps but it seems the sort functionality never worked. Anyway not an answer to my question but this is how I solved the problem:
Logic can be found at:
http://www.kryogenix.org/code/browser/sorttable/
-HaYen

C# Regex match case - split string and write to file output

Basically I have a text file of records in this format:
(1909, 'Ford', 'Model T'),
(1926, 'Chrysler', 'Imperial'),
(1948, 'Citroën', '2CV'),
That I want to output to a text file in the following format
new Vehicle() { Id = 1, Year = 1909, Make = "Ford", Model = "Model T" },
new Vehicle() { Id = 2, Year = 1926, Make = "Chrysler", Model = "Imperial" },
new Vehicle() { Id = 3, Year = 1948, Make = "Citroën", Model = "2CV" },
I know I need to split each line in to the relevant text sections, e.g. trying to follow something like this SO question. But have hit mental block on how to get the relevant matching string sections for Year, Make and Model.
So far I have found this, that finds everthing between the parentheses:
\(([^()]+)\)
But not sure how to then group the the values and split by the commas:
Any help greatly appreciated.
Regex to get them in groups:
\((\d+),\s+[']([\w\së]+)['],\s+[']([\w\s]+)[']\)[,]*
Make note there is problem about Citroën => You have to enter all the special symbols not within a-z, A-Z (like ë ü ÿ etc..)
To use in code, You will get the groups 1st:
string cars = #"(1909, 'Ford', 'Model T'),"
string pattern = #"\((\d+),\s+[']([\w\së]+)['],\s+[']([\w\s]+)[']\)[,]*";
var lResult = Regex.Match(cars, pattern);
if(lResult.Success)
foreach( var iGroup in lResult.Groups)
Console.WriteLine(iGroup);
In lResult.Groups You got the info about car, You have just output it to the file as You need.
C# 6.0:
Console.WriteLine($"new Vehicle() {{ Id = 1, Year = {lResults.Groups[1]}, Make = \"{lResults.Groups[2]}\", Model = \"{lResults.Groups[3]}\"}},");
Old syntax:
Console.WriteLine(#"new Vehicle() { Id = 1, Year = "+ lMatch.Groups[1]+", Make = "+ lMatch.Groups[2] + ", Model = "+ lMatch.Groups[3] + " },");
Once You get this automatized into for loops, You can add Id easily.
My example have in Groups[0] whole string, so this is why my indexing starting from 1 to 3.
As #Toto said, \w already includes \d, there is no need to write it then.
Why not use string.Split(',')? Would be faster than Regex and suits for you (first delete the last ',' of each line, of course.
if you are willing to use a parser framework (which is maybe a little bit of an overkill), you could use for example sprache. Example without proper error handling:
Parser<string> stringContent =
from open in Parse.Char('\'').Once()
from content in Parse.CharExcept('\'').Many().Text()
from close in Parse.Char('\'').Once()
select content;
Parser<string> numberContent = Parse.Digit.AtLeastOnce().Text();
Parser<string> element = stringContent.XOr(numberContent);
Parser<List<string>> elements =
from e in element.DelimitedBy(Parse.Char(',').Token())
select e.ToList();
Parser<List<string>> parser =
from open in Parse.Char('(').Once()
from content in elements
from close in Parse.Char(')').Once()
select content;
var input = new List<string> { "(1909, 'Ford', 'Model T')", "(1926, 'Chrysler', 'Imperial')", "(1948, 'Citroën', '2CV')" };
foreach (var line in input)
{
var parsed = parser.Parse(line);
var year = Int32.Parse(parsed[0]);
var make = parsed[1];
var model = parsed[2];
Console.WriteLine(">> " + year + " " + make + " " + model);
}
You can use this snippet based on named capture groups:
var cars = new List<string>() {
"(1909, 'Ford', 'Model T')",
"(1926, 'Chrysler', 'Imperial')",
"(1948, 'Citroën', '2CV')",
};
var regex = #"(?<Year>\d+).*?'(?<Brand>.*?)'.*?'(?<Model>.*?)'";
foreach (var car in cars)
{
var match = Regex.Match(car, regex);
if (match.Success)
{
Console.WriteLine($"{match.Groups["Brand"]} make {match.Groups["Model"]} in {match.Groups["Year"]}");
}
}
Which will print:
Ford make Model T in 1909
Chrysler make Imperial in 1926
Citroën make 2CV in 1948

Trying to compare tags in mongodb string array, with textbox input c#

Okay so i have a mongodb that has a collection that is called videos and in videos i have a field called tags. what i want to do is compare a textbox input with the tags on all videos in the collection and return them to a gridview if a tag matches the input from the textbox. When i create a new video the tags field is a string Array so it is possible to store more than one tag. I am trying to do this in c#. Hope you some of you can help thanks!
Code for creating a new video document.
#region Database Connection
var client = new MongoClient();
var server = client.GetServer();
var db = server.GetDatabase("Database");
#endregion
var videos = db.GetCollection<Video>("Videos");
var name = txtVideoName.Text;
var location = txtVideoLocation.Text;
var description = txtVideoDescription.Text;
var user = txtVideoUserName.Text;
string[] lst = txtVideoTags.Text.Split(new char[] { ',' });
var index = videos.Count();
var id = 0;
if (id <= index)
{
id += (int)index;
}
videos.CreateIndex(IndexKeys.Ascending("Tags"), IndexOptions.SetUnique(false));
var newVideo = new Video(id, name, location, description, lst, user);
videos.Insert(newVideo);
Okay so here is how the search method looks like i have just made the syntax a little diffrent from what Grant Winney ansewred.
var videos = db.GetCollection<Video>("Videos");
string[] txtInput = txtSearchTags.Text.Split(new char[] { ',' });
var query = (from x in videos.AsQueryable<Video>()
where x.Tags.ContainsAny(txtInput)
select x);
This finds all videos with tags that contain a tag specified in the TextBox, assuming the MongoDB driver can properly translate it into a valid query.
var videos = db.GetCollection<Video>("Videos")
.AsQueryable()
.Where(v => v.Tags.Split(',')
.ContainsAny(txtVideoTags.Text.Split(',')))
.ToList();
Make sure you've got using MongoDB.Driver.Linq; at the top.

Querying a list of strings with a query string?

I have a dictionary:
<string,List<string>>
The key is the product code say "product1" then the list is a list of properties:
"Brand","10.40","64","red","S"
Then I 'can' have a list of rules/filters e.g.
var tmpFilter = new customfilters();
tmpFilter.Field = "2";
tmpFilter.Expression = ">";
tmpFilter.Filter = "10";
So for the above example this would pass because at index 2 (tmpFilter.Field) it is more than 10; then I have another object which defines which fields within the list I want to write to file. For that dictionary item I just want to write the product brand and price where the filters match.
At the moment without the filter I have:
var tmp = new custom();
tmp.Columns = "0,1";
tmp.Delimiter = ",";
tmp.Extention = ".csv";
tmp.CustomFilters = new List<customfilters>() {new customfilters(){ Field = "2", Expression = ">", Filter = "10"} };
public static void Custom(custom custom)
{
foreach (var x in Settings.Prods)
{
//Get Current Product Code
var curprod = Settings.ProductInformation[x];// the dictionary value
foreach (var column in custom.Columns)
{
var curVal = curprod[Convert.ToInt32(column)];
tsw.Write(curVal + custom.Delimiter);
}
Settings.Lines++;
tsw.WriteLine();
}
tsw.Close();
}
I only want to write the curprod if all the filters pass for that list of strings.
How I can do this?
There's a really nice Nuget package based on an example published by Microsoft, that they have decided to make really hard to find for some reason, that allows dynamic linq queries:
https://www.nuget.org/packages/System.Linq.Dynamic/1.0.2
Source:
https://github.com/kahanu/System.Linq.Dynamic
Using that you can do stuff like this very easily (note: I used strings here because the OP states they have a List<string>):
List<string> stuff = new List<string> { "10.40", "64", "5", "56", "99", "2" };
var selected = stuff.Select(s => new { d = double.Parse(s) }).Where("d > 10");
Console.WriteLine(string.Join(", ", selected.Select(s => s.d.ToString()).ToArray()));
Outputs:
10.4, 64, 56, 99
That may give you a place to start. One thing you are going to have to tackle is identifying which of your fields are numeric and should be converted to a numeric type before trying to apply your filter. Otherwise you are going to comparing as strings.

SolrNet facetted search

I'm using Solr and Solrnet for the first time.
I have managed to create a schema, which has amongst them the following fields:
created_date DateTime
parent_id int
categories string multi-valued
I've been able to get a basic search working against the parent_id field, as so:
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<SolrNode>>();
ICollection<SolrNode> results = solr.Query(new SolrQueryByField("parent_id", currentNode.Id.ToString()));
I've been able to figure out (kind of) how to return facets for all of my results, as so:
var solrFacet = ServiceLocator.Current.GetInstance<ISolrOperations<SolrNode>>();
var r = solrFacet.Query(SolrQuery.All, new QueryOptions
{
Rows = 0,
Facet = new FacetParameters
{
Queries = new[] {
//new SolrFacetDateQuery("created_date", DateTime.Now /* range start */, DateTime.Now.AddMonths(-6) /* range end */, "+1DAY" /* gap */) {
// HardEnd = true,
// Other = new[] {FacetDateOther.After, FacetDateOther.Before}
//}
new SolrFacetDateQuery("created_date", new DateTime(2011, 1, 1).AddDays(-1) /* range start */, new DateTime(2014, 1, 1).AddMonths(1) /* range end */, "+1MONTH" /* gap */) {
HardEnd = true,
Other = new[] {FacetDateOther.After, FacetDateOther.Before}
}
//,
//new SolrFacetFieldQuery("categories")
},
}
});
//foreach (var facet in r.FacetFields["categories"])
//{
// this.DebugLiteral.Text += string.Format("{0}: {1}{2}", facet.Key, facet.Value, "<br />");
//}
DateFacetingResult dateFacetResult = r.FacetDates["created_date"];
foreach (KeyValuePair<DateTime, int> dr in dateFacetResult.DateResults)
{
this.DebugLiteral.Text += string.Format("{0}: {1}{2}", dr.Key, dr.Value, "<br />");
}
But what I'm not able to figure out is how to plumb it all together. My requirements are as follows:
Page loads - show all search results where parent_id matches N. Query facets of search results and show tick boxes for the facets like so:
Categories
Category 1
Category 2
Within
Last week
Last month
Last 3 months
Last 6 months
All time
User clicks on relevant tick boxes and then code executes another solr query, passing in both the parent_id criteria, along with the facets the user has selected.
I realise in my description I have simplified the process, and perhaps it is quite a big question to ask on StackOverflow, so I'm of course not expecting a working example (although if you're bored pls feel free ;-)) but could anyone provide any pointers, or examples? SolrNet does have an MVC sample app, but I'm using WebForms and not particularly comfortable with MVC just yet.
Any help would be greatly appreciated.
Thanks in advance
Al
You can club the Query and add facets as Query Opertations
ISolrQueryResults<TestDocument> r = solr.Query("product_id:XXXXX", new QueryOptions {
FacetQueries = new ISolrFacetQuery[] {
new SolrFacetFieldQuery("category")
}
});
I create a 'fq' string of the facets selected. For instance, if the user selects these facets:
united states
california
almond growers
and the facet field is 'content_type', I generate this query string:
(content_type:"united states" AND content_type:california AND content_type:"almond growers")
Note the quotes and the open and close parenthesis...important! I store this in the variable named finalFacet. I then submit it to Solr like this, where sQuery is the text the user is searching on and finalFacet is the facet query string as shown above:
articles = solr.Query(sQuery, new QueryOptions
{
ExtraParams = new Dictionary<string, string> {
{"fq", finalFacet},
},
Facet = new FacetParameters
{
Queries = new[] { new SolrFacetFieldQuery("content_type")}
},
Rows = 10
Start = 1,
});

Categories