Irrelevant search results with lucene.net - c#

I have been developing a search engine for a business directory application using Lucene.net. However when i search for Sports shop it returns the result of other shops including the sports shops because the key word shop matches with that. So how can i prioritize that it should return the results which is matches with the keyword sport
If anyone have solution for this please share here. Any helpful example or links will be appreciated.

I would very much appreciate it if you could paste some code to give you a better example.
However, from reading your question I think that what you need is a phrase query to give Sports Shop a higher boost.
My implementation of this query is this:
public List QueryToPhraseQuery(string pQuery) {
QueryParsers.Classic.MultiFieldQueryParser oPhraseParser = new QueryParsers.Classic.MultiFieldQueryParser(Version, FieldArray, Analyzer, BoostDictionary);
List<PhraseQuery> lstPhraseQuery = new List<PhraseQuery>();
HashSet<Term> lstTerms = new HashSet<Term>();
oPhraseParser.Parse(pQuery).ExtractTerms(lstTerms);
foreach (var group in lstTerms.GroupBy(x => x.Field))
{
PhraseQuery oPhraseQuery = new PhraseQuery() { Boost = 10, Slop = 3 };
foreach (var oTerm in group.ToList())
{
oPhraseQuery.Add(oTerm);
if (oTerm.Field == Field.ImportantField)
oPhraseQuery.Boost = 30;
}
lstPhraseQuery.Add(oPhraseQuery);
}
return lstPhraseQuery;
}
This would search for thing like this in your index which will match exactly and will return better results with more relevance
attributedescriptions:"something something"~3^10.0 attributemajor:"something something"~3^30.0 description:"something something"~3^10.0 edescription:"something something"~3^10.0
If you want me to give you an example using your code, just past eit and I can modify it to better fit your exam

Related

Selenium C# Find Element with class and text

im very new to testing and have no training in automated tests so please bare with me if i say stupid things but ill try the best i can.
Bascially i am trying to assert that a specific employee in the employee list has the status of 'leaver'.
This is what i have tried (and other variations with the different classes)
Assert.Equal("image-tile__badge background-color--status-leaver ng-star-inserted", Driver.FindElement(By.XPath("//*[contains(#class,'image-tile__content-header') and contains(text(),'End Date, Contract') and contains(#class, 'image-tile__badge')]")).GetAttribute("Class"));
Assert.Equal("image-tile__badge background-color--status-leaver ng-star-inserted", Driver.FindElement(By.XPath("//*[contains(#class,'image-tile__content-header') and contains(text(),'End Date, Contract')]")).FindElement(By.XPath("//*[contains(#class, 'image-tile__badge')]")).GetAttribute("Class"));
The last one finds the element when the status is 'new', but when i change the employee status to 'leaver', it still returns as 'new' so possibly looking at another employee with a 'new' status.
Hopefully this is enough info, let me know if more is needed (this is my first ever post!)
HTML code in image below
[HTML code on Chrome]
[1]: https://i.stack.imgur.com/kUxkf.png
Summary: im trying to assert that the Employee "End Date, Contract" has the status of leaver (aka the leaver class "image-tile__badge background-color--status-leaver ng-star-inserted")
Thanks everyone for their help!
One of my devs managed to take #noldors example and modify it a bit so heres what ended up working for me:
var newElmList1 = Driver.FindElements(By.CssSelector("div.background-color--status-leaver")).ToList();
List<string> newNames1 = new List<string>();
foreach (var newElm in newElmList1)
{
var newName1 = newElm.FindElement(By.XPath(".."))
.FindElement(By.CssSelector("div.image-tile__content-header")).Text;
newNames.Add(newName1);
}
if (!newNames.Contains("End Date, Contract"))
{
throw new Exception("Exception Error on leaver Person");
}
As per your screenshot i fill it's better if you try using Xpath
var elmList = Driver.FindElements(By.Xpath("//div[contains(text(),'leaver')]")).ToList();
i hope it will help you
Thank You.
According to your screenshot, you can find all elements with 'Leaver' specific class with this;
var leaverElmList = Driver.FindElements(By.CssSelector("div.background-color--status-leaver")).ToList();
List<string> leaverNames = new List<string>();
foreach (var leaverElm in leaverElmList) {
var leaverName = leaverElm.FindElement(By.XPath(".."))
.FindElement(By.CssSelector("div.image-tile__content-header"));
.Text()
leaverNames.Add(leaverName);
}
Enddate, Contract which is not related to the div that contains Leaver. It's direct parent is the image-tile div

Find within large list using Contains within Linq

I have two large excel files. I am able to get the rows of these excel files into a list using linqtoexcel. The issue is that I need to use a string from one object within the first list to find if it is part of or contained inside another string within an object of the second list. I was trying the following but the process is taking to long as each list is over 70,000 items.
I have tried using an Any statement but have not be able to pull results. If you have any ideas please share.
List<ExcelOne> exOne = new List<ExcelOne>();
List<ExcelTwo> exTwo = new List<ExcelTwo>();
I am able to build the first list and second list and can verify there are objects in the list. Here was my thought of how I would work through the lists to find matching. Note that once I have found the matching I want to create a new class and add it to a new list.
List<NewFormRow> rows = new List<NewFormRow>();
foreach (var item in exOne)
{
//I am going through each item in list one
foreach (var thing in exTwo)
{
//I now want to check if exTwo.importantRow has or
//contains any part of the string from item.id
if (thing.importantRow.Contains(item.id))
{
NewFormRow adding = new NewFormRow()
{
Idfound = item.id,
ImportantRow = thing.importantRow
};
rows.Add(adding);
Console.WriteLine("added one");
}
}
If you know a quicker way around this please share. Thank you.
It's hard to improve this substring approach. The question is if you have to do it here. Can't you do it where you have filled the lists? Then you don't need this additional step.
However, maybe you find this LINQ query more readable:
List<NewFormRow> rows = exOne
.SelectMany(x => exTwo
.Where(x2 => x2.importantRow.Contains(x.id))
.Select(x2 => new NewFormRow
{
Idfound = x.id,
ImportantRow = x2.importantRow
}))
.ToList();

c# arraylist searching confusion

I am having problems searching through my Arraylist. The array list stores various information about a number of teams such as the image path to their logo and the team name etc. It is being filled from a separate datafile using a StreamReader
I would like the user to input something in a Textbox from a windows form such as the team name and then consequently the program will then search my arraylist for said string and open another form where the information of the searched team will be loaded up on screen using the Form.Load procedure
To put it simply.
private void btn_Search_Click(object sender, EventArgs e)
{
//what code do I write here?
}
I understand that I might be a little to deep here for my current knowledge of coding so help would be appreciated.
EDIT: unfortunately it must be in an arraylist, sorry for the inconvenience.
If you can use LINQ:
string nameToMatch = "Tigers"; //can you tell who's from Michigan?
List<Team> teams = new ArrayList<Team>();
//fill team data here
Team selected = teams.FirstOrDefault(t => t.TeamName.Equals(nameToMatch, StringComparison.OrdinalIgnoreCase));
Something like this should work. (This will match the text exactly but allow the search to be case insensitive. You can read about other options here.)
If you want to match a list of all "partial matches", you can do this instead:
List<Team> matchedTeams = teams.Select(t => t.TeamName.Contains(nameToMatch));
Read here for an extension overload of Contains that takes a StringComparison enum value.
If you're unfamiliar with LINQ like I am you could use a foreach loop. Something like this:
String nameToMatch = textBox1.text; //read from the text box
foreach (Object obj in Teams)
{
MyTeam team = (MyTeam)obj; //MyTeam is an object you could write that would store team information.
if (team.TeamName.ToUpper() == nameToMatch.ToUpper()) //case insensitive search.
{
FormTeam frmTeam = new FormTeam(team); //windows form that displays team info.
frmTeam.Visible = true;
break; //if team names are unique then stop searching.
}
}
Worst case senario is pretty bad, but for me, at least, it's easier to get my head around than LINQ. Good Luck, hope that helps.
You can use some codes like this to fill your arraylist:
// ArrayList class object
ArrayList arrlist = new ArrayList();
// add items to arrlist collection using Add method
arrlist.Add("item 1");
arrlist.Add("item 2");
arrlist.Add("item 3");
arrlist.Add("item 4");
arrlist.Add("item 5");
and use some codes like this to search in your arraylist
string teamName= this.txtTeamName.Text;
// for loop to get items stored at each index of arrlist collection
for (int i = 0; i < arrlist.Count; i++)
{
if(arrlist[i].toString()==teamName)
// open a new form for show the found team details
}
it is a good practice to change the cunstractor of your "Team Details" form to get a "team name"
frmTeamDetails(team myteam)
then use this code in the above FOR statement:
frmTeamDetals frm=new frmTeamDetals(teamName);
frm.ShowDialog();

C# Reading and Summarizing Text File with LINQ

I've read MANY different solutions for the separate functions of LINQ that, when put together would solve my issue. My problem is that I'm still trying to wrap my head about how to put LINQ statements together correctly. I can't seem to get the syntax right, or it comes up mish-mash of info and not quite what I want.
I apologize ahead of time if half of this seems like a duplicate. My question is more specific than just reading the file. I'd like it all to be in the same query.
To the point though..
I am reading in a text file with semi-colon separated columns of data.
An example would be:
US;Fort Worth;TX;Tarrant;76101
US;Fort Worth;TX;Tarrant;76103
US;Fort Worth;TX;Tarrant;76105
US;Burleson;TX;Tarrant;76097
US;Newark;TX;Tarrant;76071
US;Fort Worth;TX;Tarrant;76103
US;Fort Worth;TX;Tarrant;76105
Here is what I have so far:
var items = (from c in (from line in File.ReadAllLines(myFile)
let columns = line.Split(';')
where columns[0] == "US"
select new
{
City = columns[1].Trim(),
State = columns[2].Trim(),
County = columns[3].Trim(),
ZipCode = columns[4].Trim()
})
select c);
That works fine for reading the file. But my issue after that is I don't want the raw data. I want a summary.
Specifically I need the count of the number of occurrences of the City,State combination, and the count of how many times the ZIP code appears.
I'm eventually going to make a tree view out of it.
My goal is to have it laid out somewhat like this:
- Fort Worth,TX (5)
- 76101 (1)
- 76103 (2)
- 76105 (2)
- Burleson,TX (1)
- 76097 (1)
- Newark,TX (1)
- 76071 (1)
I can do the tree thing late because there is other processing to do.
So my question is: How do I combine the counting of the specific values in the query itself? I know of the GroupBy functions and I've seen Aggregates, but I can't get them to work correctly. How do I go about wrapping all of these functions into one query?
EDIT: I think I asked my question the wrong way. I don't mean that I HAVE to do it all in one query... I'm asking IS THERE a clear, concise, and efficient way to do this with LINQ in one query? If not I'll just go back to looping through.
If I can be pointed in the right direction it would be a huge help.
If someone has an easier idea in mind to do all this, please let me know.
I just wanted to avoid iterating through a huge array of values and using Regex.Split on every line.
Let me know if I need to clarify.
Thanks!
*EDIT 6/15***
I figured it out. Thanks to those who answered it helped out, but was not quite what I needed. As a side note I ended up changing it all up anyways. LINQ was actually slower than doing it other ways that I won't go into as it's not relevent. As to those who made multiple comments on "It's silly to have it in one query", that's the decision of the designer. All "Best Practices" don't work in all places. They are guidelines. Believe me, I do want to keep my code clear and understandable but I also had a very specific reasoning for doing it the way I did.
I do appreciate the help and direction.
Below is the prototype that I used but later abandoned.
/* Inner LINQ query Reads the Text File and gets all the Locations.
* The outer query summarizes this by getting the sum of the Zips
* and orders by City/State then ZIP */
var items = from Location in(
//Inner Query Start
(from line in File.ReadAllLines(FilePath)
let columns = line.Split(';')
where columns[0] == "US" & !string.IsNullOrEmpty(columns[4])
select new
{
City = (FM.DecodeSLIC(columns[1].Trim()) + " " + columns[2].Trim()),
County = columns[3].Trim(),
ZipCode = columns[4].Trim()
}
))
//Inner Query End
orderby Location.City, Location.ZipCode
group Location by new { Location.City, Location.ZipCode , Location.County} into grp
select new
{
City = grp.Key.City,
County = grp.Key.County,
ZipCode = grp.Key.ZipCode,
ZipCount = grp.Count()
};
The downside of using File.ReadAllLines is that you have to pull the entire file into memory before operating over it. Also, using Columns[] is a bit clunky. You might want to consider my article describing using DynamicObject and streaming the file as an alternative implemetnation. The grouping/counting operation is secondary to that discussion.
var items = (from c in
(from line in File.ReadAllLines(myFile)
let columns = line.Split(';')
where columns[0] == "US"
select new
{
City = columns[1].Trim(),
State = columns[2].Trim(),
County = columns[3].Trim(),
ZipCode = columns[4].Trim()
})
select c);
foreach (var i in items.GroupBy(an => an.City + "," + an.State))
{
Console.WriteLine("{0} ({1})",i.Key, i.Count());
foreach (var j in i.GroupBy(an => an.ZipCode))
{
Console.WriteLine(" - {0} ({1})", j.Key, j.Count());
}
}
There is no point getting everything into one query. It's better to split the queries so that it would be meaningful. Try this to your results
var grouped = items.GroupBy(a => new { a.City, a.State, a.ZipCode }).Select(a => new { City = a.Key.City, State = a.Key.State, ZipCode = a.Key.ZipCode, ZipCount = a.Count()}).ToList();
Result screen shot
EDIT
Here is the one big long query which gives the same output
var itemsGrouped = File.ReadAllLines(myFile).Select(a => a.Split(';')).Where(a => a[0] == "US").Select(a => new { City = a[1].Trim(), State = a[2].Trim(), County = a[3].Trim(), ZipCode = a[4].Trim() }).GroupBy(a => new { a.City, a.State, a.ZipCode }).Select(a => new { City = a.Key.City, State = a.Key.State, ZipCode = a.Key.ZipCode, ZipCount = a.Count() }).ToList();

Store search results for later use - Accessing results view

I have a c# asp.net MVC project. I am doing a a search and want to access the search results on the details page of one of the search results.
This is so that I can have < prev | next > links on the detail pages that will link to the next property in the last search results.
My approach so far is to put the search results object into a session variable, but I can't figure out the code to actually access it. When I do a watch on Session["SearchResults"] below, I can see the records in the Result View, which seems to hold an array.
I know someone is going to tell me I'm thinking about this all wrong, and I can't wait to be enlightened.
Someone suggested I should just store the last search results on the repository as a public property, would that be a better option? Or can someone recommend an altogether better way of doing what I need to do?
This is my controller
public ActionResult Search(int? page, Search search)
{
search.regusApi = Convert.ToBoolean(ConfigurationManager.AppSettings["regusApiLiveInventory"]);
Session["SearchResults"] = MeetingRoomRepositoryWG.Search(search).AsPagination(page ?? 1, 7);
return View(new SearchResultsWG { SearchCriteria = search, Locations = MeetingRoomRepositoryWG.Search(search).AsPagination(page ?? 1, 7) });
}
public ActionResult NiceDetails(String suburb, String locationName, int id)
{
**Here I want to acceess the session variable**
return View(MeetingRoomRepositoryWG.RoomDetails(id).First());
}
Here is the code from the repository:
public static List<Location> Search(Search search)
{
String LongLatString = search.LongLat;
LongLatString = LongLatString.Substring(1, LongLatString.Length - 2);
var LonLatSplit = LongLatString.Split(',');
var latitude = Convert.ToDecimal(LonLatSplit[0]);
var longitude = Convert.ToDecimal(LonLatSplit[1]);
using (var context = new MyContext())
{
var query = context.Locations.Include("Location_LonLats").ToList();
query.OrderBy(x => (Convert.ToDecimal(x.Location_LonLats.Lat) - latitude) * (Convert.ToDecimal(x.Location_LonLats.Lat) - latitude)
+ (Convert.ToDecimal(x.Location_LonLats.Lon) - longitude) * (Convert.ToDecimal(x.Location_LonLats.Lon) - longitude));
return query;
}
}
Not sure how large the data is you search against but, it's better to not store search results at all. It will scale very poorly and become a resource hog quite easily. Why store e.g. 500 pages of search results if the user only ends up looking at 1 or 3?
How long are you going to hold these potentially large result sets in session storage? For how many users?
Just do a page based search, essentially redoing the search for each "next" click the client does. A good index or something like Lucene.net can help if your searches are too slow.

Categories

Resources