I'm trying to build a lucene query through Sitecore ContentSearch that includes an optional term. The optional term is used to boost certain results. The lucene query should look like this:
+(+(_content:myquery keywords:myquery) boostfield:boostdata)
How can I construct such a query? With PredicateBuilder I can only add And / Or expressions.
Here's an example of how I construct the predicate:
var contentPredicate = PredicateBuilder.Create<MySearchResultItem>(p => p.Content == parameters.QueryString);
contentPredicate = contentPredicate.Or(k => k.Keywords == "myquery");
mainPredicate = mainPredicate.And(contentPredicate);
mainPredicate = mainPredicate.And(f => f["boostfield"] == "boostdata");
This will make "boostfield" a must field wich is not what I need (note the + before the field name):
+(+(_content:myquery keywords:myquery) +boostfield:boostdata)
Is there a way to accomplish this?
Try This:
var contentPredicate = PredicateBuilder.Create<MySearchResultItem>(p => p.Content == parameters.QueryString);
contentPredicate = contentPredicate.Or(k => k.Keywords == "myquery");
mainPredicate = mainPredicate.And(contentPredicate);
var boostQuery = PredicateBuilder.False<MySearchResultItem>();
boostQuery = boostQuery.Or(f => f["boostfield"] == "boostdata");
mainPredicate = mainPredicate.Or(boostQuery)
I think it could get you the results you need.
If you are simply looking to boost results based on an optional field, you can have your predicate builder as follows:
boostfield.contains("term") or field.contains("term")
And then increase the boost value in the standard fields for the field item itself. The order in which you build the predicate has a bearing on the results so make sure you check against the boost field first.
Related
I'm working with a legacy Oracle database that has a column on a table which stores boolean values as 'Y' or 'N' characters.
I have mapped/converted this column out like so:
MappingSchema.Default.SetConverter<char, bool>(ConvertToBoolean);
MappingSchema.Default.SetConverter<bool, char>(ConvertToChar);
ConvertToBoolean & ConvertToChar are simply functions that map between the types.
Here's the field:
private char hasDog;
[Column("HAS_DOG")]
public bool HasDog
{
get => ConvertToBoolean(hasDog);
set => hasDog = ConvertToChar(value);
}
This has worked well for simply retrieving data, however, it seems the translation of the following:
var humanQuery = (from human in database.Humans
join vetVisit in database.VetVisits on human.Identifier equals vetVisit.Identifier
select new HumanModel(
human.Identifier
human.Name,
human.HasDog,
vetVisit.Date,
vetVisit.Year,
vetVisit.PaymentDue
));
// humanQuery is filtered by year here
var query = from vetVisits in database.VetVisits
select new VetPaymentModel(
(humanQuery).First().Year,
(humanQuery).Where(q => q.HasDog).Sum(q => q.PaymentDue), -- These 2 lines aren't correctly translated to Y/N
(humanQuery).Where(q => !q.HasDog).Sum(q => q.PaymentDue)
);
As pointed out above, the .Where clause here doesn't translate the boolean comparison of HasDog being true/false to the relevant Y/N values, but instead a 0/1 and results in the error
ORA-01722: invalid number
Is there any way to handle this case? I'd like the generated SQL to check that HAS_DOG = 'Y' for instance with the specified Where clause :)
Notes
I'm not using EntityFramework here, the application module that this query exists in doesn't use EF/EFCore
You can define new mapping schema for your particular DataConnection:
var ms = new MappingSchema();
builder = ms.GetFluentMappingBuilder();
builder.Entity<Human>()
.Property(e => e.HasDog)
.HasConversion(v => v ? 'Y' : 'N', p => p == 'Y');
Create this schema ONCE and use when creating DataConnection
I'm calling the sql server function Contains like this :
ftquery = _OrElse(ftquery,Restrictions.Eq(Projections.SqlFunction("contains",NHibernateUtil.Boolean, Projections.Property<Document>(d => d.SearchContent), Projections.Constant(query.Query)),true));
OrElse will juste do an or using Restrictions.Or(ICriterion, ICriterion). The problem is that it generates invalid sql :
... and contains(this_.SearchContent, ?) = ? ORDER BY ...
I don't want to have the right part ( = ? ), I only need the Projection without the Restrictions.Eq, but without Restrictions.Eq I can't find any solution to convert a Projection to a Criterion.
How can we using NHibernate generate an sql like :
Select Name from Users where Contains(Name,'toto') or Contains(Job,'tata')
Register the function in your dialect:
RegisterFunction("FullTextContains", new StandardSQLFunction("contains", NHibernateUtil.Boolean));
Create a projection using Projections.SqlFunction then use this ProjectionAsCriterion class on your query:
var projection = Projections.SqlFunction("FullTextContains",
NHibernateUtil.Boolean,
Projections.Property<Document>(x => x.SearchContent),
Projections.Constant(query.Query));
var result = Session.QueryOver<Document>()
.Where(new ProjectionAsCriterion(projection))
.List();
Why is there a OR instead of an AND between the SEARCH and the WHERE?
The problem is that the current Lucene query is:
"OrganizationType:Boo ( Name:(Foo) ShortName:(Foo))"
instead of:
"OrganizationType:Boo AND ( Name:(Foo) ShortName:(Foo))"
How can I change that?
RavenQueryStatistics stats;
var organizationQuery = session.Query<Organization>()
.Statistics(out stats)
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize);
if (request.OrganizationType != default(OrganizationType))
{
organizationQuery = organizationQuery.Where(o => o.OrganizationType == request.OrganizationType);
}
if (!string.IsNullOrEmpty(request.Query))
{
organizationQuery = organizationQuery
.Search(c => c.Name, request.Query, escapeQueryOptions: EscapeQueryOptions.AllowPostfixWildcard)
.Search(c => c.ShortName, request.Query, escapeQueryOptions: EscapeQueryOptions.AllowPostfixWildcard);
}
I have added a screenshot with the proposed solution:
To get only documents matching all sub-queries you to have to use Intersect. See the article How to use intersect in the RavenDB documentation.
Because Search is using OR by default. There is an optional parameter that set it to use AND.
I'm trying to run a "where" query to find a domain model object that has no association with another domain model object or if it does, that domain model object has a specific property value. Here's my code:
query = Model.where({
other == null || other.something == value
})
def list = query.list()
However, the resulting list only contains objects that match the second part of the OR statement. It contains no results that match the "other == null" part. My guess is that since it's checking a value in the associated object its forcing it to only check entries that actually have this associated object. If that is the case, how do I go about creating this query and actually having it work correctly?
You have to use a LEFT JOIN in order to look for null associations. By default Grails uses inner join which will not be joined for null results. Using withCriteria as below you should get the expected results:
import org.hibernate.criterion.CriteriaSpecification
def results = Model.withCriteria {
other(CriteriaSpecification.LEFT_JOIN){
or{
isNull 'id'
eq 'something', value
}
}
}
UPDATE
I know aliasing is not possible in DetachedCritieria where one would try to specify the join as in createCriteria/withCriteria. There is an existing defect regarding adding the functionality to DetachedCriteria. Just adding the work around for where query as mentioned in defect.
Model.where {
other {
id == null || something == value
}
}.withPopulatedQuery(null, null){ query ->
query.#criteria.subcriteriaList[0].joinType = CriteriaSpecification.LEFT_JOIN
query.list()
}
I would rather use withCriteria instead of the above hack.
this might work:
query = Model.where({
isNull( other ) || other.something == value
})
If that wouldn't work, try something like:
other.id == null || other.something == value
UPDATE:
or with good'ol criteria query:
list = Pack.withCriteria{
or{
isNull 'other'
other{ eq 'something', value }
}
}
I have been struggling to get this working. I wish to have an EF statement take in a column to order by. My original statement was this:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
And I changed this to the following:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby sortField
select P;
Where sortField is the column we wish to sort on, and is a string i.e. LastName. However, it does not appear to work, it does no sorting, and the outputted SQL string is completely wrong. Anyone got this working before?
you could try passing in an expression to your method with the following type:
Expression<Func<Person, object>> expr = p => p.LastName;
and then using linq extensions instead of linq expressions...
var Query =
DbContext.People
.Where(P => P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId))
.OrderBy(expr)
.ToList();
Your sort does not work because you are sorting on a string literal. It is not illegal, but it is not particularly useful either. You need to provide a sorting field through the API of IQueryable<T>, for example, like this:
var q = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
if ("sortField".Equals("FirstName"))
q = q.OrderBy(p => p.FirstName);
else if ("sortField".Equals("LastName"))
q = q.OrderBy(p => p.LastName);
else if ("sortField".Equals("Dob"))
q = q.OrderBy(p => p.Dob);