How to search by multi Category IDs with OR Boolean opeeation at Lucence - lucene.net

How to search by multi Category IDs with OR Boolean opeeation at Lucence
We have CategoryID as field at Lucene index, when we are using single value to search in CategoryID field, it is working fine but if we are passing multi values the search doesn't return a values
Example:
Category IDs = 10, 20, 30
Search Data:
Category ID = 10
Results:
It is working fine
Search Data:
Category ID = 10, 20
Results:
It is not working
// search in categories
if (checkedCategories != null && checkedCategories.Count > 0)
{
foreach (int categoryID in checkedCategories)
{
Query queryEntity = new TermQuery(new Term("CategoryID", categoryID.ToString()));
booleanQuery.Add(queryEntity, Occur.MUST);
}
}

I found the answer, it is into the following great article
http://searchhub.org/2011/12/28/why-not-and-or-and-not/
What I did to solve my problem is:
Search by Lucene_KsuDmsDesc = A
Search by Lucene_EmployeeNO = B
Search by Lucene_CreatedBy = C
Search by Lucene_CreatedDateTime = D
Search by Lucene_CategoryID = E
The formula is (A and B and C and D) and (E1 or E2 or .... En), where and = MUST and or = SHOULD

Related

I want to make MongoEngine Query that just return the vehicle that i want, but it doesnt work

I'm using MongoEngine to create a query that return just vehicles that match with the constraint. As can you see Vehicle is an EmbeddedDocument and Owner is the parent document. My query is using Q, the result of the query is different that just vehicles matched with Honda brand and Element model.
from mongoengine.queryset.visitor import Q
def get_vehicles():
vehicles = json.loads(Owner.objects(Q(vehicle__brand='Honda') and Q(vehicle__model='Element')).only('vehicle').to_json())
return {"vehicles":vehicles}
class Vehicle(engine.EmbeddedDocument):
model = engine.StringField(required=True, max_length=50)
brand = engine.StringField(required=True, max_length=100)
plates = engine.StringField(required=True, max_length=50)
year = engine.IntField(required=True)
color = engine.StringField(required=True, max_length=80)
type = engine.StringField(required=True, max_length=80)
subtype = engine.StringField(required=True, max_length=80)
doors = engine.IntField(required=True)
transmission = engine.StringField(required=True, max_length=80)
photos = engine.ListField(engine.StringField(max_length=150))
equipment = engine.ListField(engine.StringField(max_length=80))
powered_by = engine.StringField(required=True, max_length=80)
availability = engine.ListField(engine.DateField())
pickup_place = engine.PointField()
creation_date = engine.DateTimeField(required=True)
class Owner(engine.Document):
_id = engine.ObjectIdField()
name = engine.StringField(required=True, max_length=100)
surname = engine.StringField(required=True, max_length=100)
gender = engine.StringField(required=True, max_length=1)
birthday = engine.DateField(required=True)
creation_date = engine.DateTimeField(required=True)
last_update = engine.DateTimeField()
photo = engine.StringField(required=True, max_length=200)
access = engine.EmbeddedDocumentField(Access)
address = engine.EmbeddedDocumentField(Address)
vehicle = engine.EmbeddedDocumentListField(Vehicle)
i'm near to the result that i want, but i need to add the result the owner id to vehicle.
def get_vehicles():
matched_owners = json.loads(Owner.objects(Q(vehicle__brand='VW') and Q(vehicle__model='Jetta')).only('vehicle').to_json())
vehicles = [ vehicle for owner in matched_owners for vehicle in owner['vehicle'] if vehicle['brand'] == "VW" and vehicle['model'] == "Jetta"]
return {"vehicles":vehicles}
The query on Mongo shell that match with the result that i want is:
db.owner.find({"vehicle.brand":"VW"},{vehicle:{$elemMatch:{model:"Jetta"}}});
I get the result that i want on MongoShell
db.owner.aggregate([{ $unwind:"$vehicle"}, {$match:{ "vehicle.model":"Jetta", "vehicle.brand":"VW"}}, {$project: {"vehicle.model":1, "vehicle.brand":1, "vehicle.color":1, "vehicle.doors":1, "vehicle.transmission":1, "vehicle.powered_by":1 ,"vehicle.photos":1, "vehicle.equipment":1, "vehicle.availability":1, "vehicle.pickup_place":1}} ]);```
i attempted to do the same on MongoEngine, but the result is different:
```python
def get_vehicles():
pipeline = [
{ "$unwind":"$vehicle"},
{
"$match":{ "vehicle.model":"Jetta", "vehicle.brand":"VW"}
},
{
"$project": {"vehicle.model":1, "vehicle.brand":1, "vehicle.color":1, "vehicle.doors":1, "vehicle.transmission":1, "vehicle.powered_by":1 ,"vehicle.photos":1, "vehicle.equipment":1, "vehicle.availability":1, "vehicle.pickup_place":1}
}
]
vehicles = Owner.objects.aggregate(pipeline)
return {"vehicles":vehicles}```
Indeed you are querying the parent collection (Owner) so the query returns all owner document with any of the Vehicle matching your Q conditions.
Although not elegant, adding a second filtering pass in Python will do the trick:
from mongoengine import *
connect()
class Vehicle(EmbeddedDocument):
model = StringField(required=True, max_length=50)
brand = StringField(required=True, max_length=100)
def __repr__(self):
return f'Vehicle({self.brand} - {self.model})'
class Owner(Document):
vehicles = EmbeddedDocumentListField(Vehicle)
Owner(vehicles=[Vehicle(model="Civic", brand="Honda"), Vehicle(model="Element", brand="Honda")]).save()
Owner(vehicles=[Vehicle(model="Golf", brand="VW")]).save()
def get_vehicles(brand, model):
matched_owners = Owner.objects(Q(vehicles__brand=brand) and Q(vehicles__model=model)).only('vehicles')
vehicles = [vehicle for owner in matched_owners for vehicle in owner.vehicles if vehicle.brand == brand and vehicle.model == model]
return vehicles
get_vehicles("Honda", "Element") # Print [Vehicle(Honda - Element)]
What you want is probably feasible using an aggregation pipeline but if your use case is really this one, you'll be just fine with this
Off topic but I'd recommend you to avoid defining a '_id' attribute, MongoEngine gives you a id = ObjectIdField() field by default and uses "_id" attribute internally so it's not a good idea to overwrite it (main MongoEngine contributor here)

Optional compare in query

Hi i have a problem with my query because i want select that items which brands are called in string subcategory. But if that subcategory is equal "none" i would to select them all i want to do it in query not in linq. Here's my function
string subcategory = HttpContext.Current.Session["subcategory"].ToString() == "none" ? "" : HttpContext.Current.Session["subcategory"].ToString();
List<int> processors = (from x in context.Processors
where (x.Price >= filters.PriceMin && x.Price <= filters.PriceMax)
where x.Brand == subcategory
select x.Product_ID).ToList();
The pattern for this in LINQ and EF is to build up the query differently for the two cases before the query is executed by calling IQueryable.ToList(); eg:
string subcategory = ...;
var q = from x in context.Processors
where (x.Price >= filters.PriceMin && x.Price <= filters.PriceMax)
select x;
if (subcategory != "none")
{
q=q.Where(x => x.Brand == subcategory);
}
var processors = q.Select(x => x.Product_ID).ToList();

flask_mongo_engine how to paginate order by create_time desc?

class Session(db.DynamicDocument):
title = db.StringField(required=False)
created = db.FloatField(required=True)
source = db.StringField()
#app.route('/page/<int:page>')
def sessions(page):
return jsonify(Session.objects.paginate(page=page, per_page=5).items)
The response is list of dict which is ordered ASC and first page contains the oldest documents by default.
So how to get the desc order result?
Just add order_by() before paginate().
keys may be prefixed with + or - to determine the ordering direction
Just an example:
class Session(db.DynamicDocument):
create_time = db.DateTimeField(required=True)
# clean before test
for i in Session.objects.all():
i.delete()
for i in range(20):
create_time = datetime.now()
create_time = create_time.replace(year=2000 + i)
ses = Session(create_time=create_time)
ses.save()
print('2000 -> 2009')
items = Session.objects.order_by('create_time').paginate(page=1, per_page=10).items
for i in items:
print(i.create_time)
print('2019 -> 2010')
items = Session.objects.order_by('-create_time').paginate(page=1, per_page=10).items
for i in items:
print(i.create_time)
Hope this helps.

How to Include a count(*) as additional result field of a query in LINQ

Given a table of players (users) with several fields. One of this is their rating with respect other players.
I'd like to implement via LINQ following SQL query:
SELECT p.*,
(select COUNT(*) from Users where (Rating > p.Rating)) as Rank
FROM Users as p
ORDER BY p.Rating DESC
In other words, last field (RANK) should give the rank of each user with respect the others:
Id Username ... Rating Rank
43 player41 ... 1002,333 0
99 player97 ... 1002 1
202 player200 ... 1002 1
53 player51 ... 1000,667 2
168 player166 ... 1000,667 2
56 player54 ... 1000 3
32 player30 ... 999,342 4
This attempt does not work:
var q = from u in Users
orderby u.Rating descending
group u by u.Id into g
select new
{
MyKey = g.Key,
User = g.First(),
cnt = Users.Count(uu => uu.Rating > g.First().Rating) + 1
};
Just for your knowledge, note that the table Users is mapped to a EF entity named User with a 'NotMapped' int? field named Rank where I'd like to manually copy the rank:
class User {
...
[NotMapped]
public virtual int? Rank { get; internal set; }
}
You'll want something like:
var rankedUsers = db.Users
.Select(user => new
{
User = user,
Rank = db.Users.Count(innerQueryUser => innerQueryUser.Rating > user.Rating)
})
.ToList();
Which will give you a list of users and their Rank as an anonymous type.
You'll then be able to do something like:
List<User> users = rankedUsers.Select(rankedUser=>
{
rankedUser.User.Rank = rankedUser.Rank;
return rankedUser.User;
})
.ToList();
Try this:
var q = (from u in Users
select new
{
UserId = u.Id,
UserObj = u,
Rank = (from u1 in Users where u1.Rating>u.Rating select u1).Count()
}).ToList();

EF Left joining a table on two properties combined with a case statement

I'm trying to write a query for a database that will left join a table to a look up table and the results will be returned based on a case statement.
In normal SQL the query would look like this:
SELECT chis_id, chis_detail, cilt.mhcatID, cilt.mhtID, 'TheFileName' =
CASE
WHEN cilt.mhcatID IS NOT NULL AND cilt.mhtID IS NOT NULL THEN chis_linked_filename
END
FROM chis
LEFT JOIN cilt on cilt.mhcatID = chis.mhcat_id AND cilt.mhtID = chis.mht_id
WHERE cch_id = 50
chis is the table being queried, cilt is a look-up table and does not contain any foreign key relationships to chis as a result (chis has existing FK's to mht and mhcat tables by the mhtID and mhcatID respectively).
The query will be used to return a list of history updates for a record. If the join to the cilt lookup table is successful this means that the caller of the query will have permission to view the filename of any associated files for the history updates.
Whilst during my research I've found various posts on here relating on how to do case statements and left joins in Linq to Entity queries, I've not been able to work out how to join on two different fields. Is this possible?
You need to join on an anonymous type with matching field names like so:
var query = from x in context.Table1
join y in context.Table2
on new { x.Field1, x.Field2 } equals new { y.Field1, y.Field2 }
select {...};
A full working example using the an extra from instead of a join would look something like this:
var query = from chis in context.Chis
from clit in context.Clit
.Where(x => x.mhcatID = chis.mhcat_id)
.Where(x => x.mhtID = chis.mht_id)
.DefaultIfEmpty()
select new
{
chis.id,
chis.detail,
cilt.mhcatID,
cilt.mhtID,
TheFileName = (cilt.mhcatID != null && cilt.mhtID != null) ? chis.linked_filename : null
};
Based on what Aducci suggested, I used a group join and DefaultIsEmpty() to get the results I wanted. For some reason, I couldn't get DefaultIfEmpty() didn't work correctly on its own and the resulting SQL employed an inner join instead of a left.
Here's the final code I used to get the left join working:
var query = (from chis in context.chis
join cilt in context.cilts on new { MHT = chis.mht_id, MHTCAT = chis.mhcat_id } equals new { MHT = cilt.mhtID, MHTCAT = cilt.mhcatID } into tempCilts
from tempCilt in tempCilts.DefaultIfEmpty()
where chis.cch_id == 50
select new {
chisID = chis.chis_id,
detail = chis.chis_detail,
filename = chis.chis_linked_filename,
TheFileName = (tempCilt.mhcatID != null && tempCilt.mhtID != null ? chis.chis_linked_filename : null),
mhtID = chis.mht_id,
mhtcatID = chis.mhcat_id
}).ToList();