I have several different mappings for a field. I have one field that is phonetic. I would like to do a query with fuzziness, but not use fuzziness on the phonetic field.
...
_client.Search<JobModelSummary>(s => s
.Index(indexName)
.Query(q => q
.MultiMatch(m => m
.Query(paginationQuery.Search)
.Type(TextQueryType.MostFields)
.Fuzziness(Fuzziness.EditDistance(1))
.Fields(f => f
.Field(ff => ff.Name.Suffix("standard"), 3)
.Field(ff => ff.Name.Suffix("edge-ngram"), 2)
.Field(ff => ff.Name.Suffix("phonetic")) // <--- Don't want this fuzzy
))));
The documentation is sparse and I am finding it difficult to peace together how this would be done.
If you're performing a most fields multi_match query as above, you can achieve what you'd like by combining several match queries together
var indexName = "foo";
var search = "search";
var searchResponse client.Search<JobModelSummary>(s => s
.Index(indexName)
.Query(q => q
.Bool(b => b
.Should(sh => sh
.Match(m => m
.Query(search)
.Fuzziness(Fuzziness.EditDistance(1))
.Field(ff => ff.Name.Suffix("standard"))
.Boost(3)
), sh => sh
.Match(m => m
.Query(search)
.Fuzziness(Fuzziness.EditDistance(1))
.Field(ff => ff.Name.Suffix("edge-ngram"))
.Boost(2)
), sh => sh
.Match(m => m
.Query(search)
.Field(ff => ff.Name.Suffix("phonetic"))
)
)
)
)
);
which can be made slightly more succinct with using the overload operators for queries
client.Search<JobModelSummary>(s => s
.Index(indexName)
.Query(q => q
.Match(m => m
.Query(search)
.Fuzziness(Fuzziness.EditDistance(1))
.Field(ff => ff.Name.Suffix("standard"))
.Boost(3)
) || q
.Match(m => m
.Query(search)
.Fuzziness(Fuzziness.EditDistance(1))
.Field(ff => ff.Name.Suffix("edge-ngram"))
.Boost(2)
) || q
.Match(m => m
.Query(search)
.Field(ff => ff.Name.Suffix("phonetic"))
)
)
);
Both produce
POST http://localhost:9200/foo/jobmodelsummary/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"name.standard": {
"boost": 3.0,
"query": "search",
"fuzziness": 1
}
}
},
{
"match": {
"name.edge-ngram": {
"boost": 2.0,
"query": "search",
"fuzziness": 1
}
}
},
{
"match": {
"name.phonetic": {
"query": "search"
}
}
}
]
}
}
}
The scores for each query in the should clause will be added together to provide the final _score for each document. With only should clauses specified, at least one has to match for a document to be considered a match.
Related
as am a beginner,i want to get the following set of query as linq with a detailed explanation
//my sql
select COL.title as organizationtitle,CL.[title] as
cousestitle,sum(FD.feathers) as totalfeathers,sum(FD.amount) as
totalamount
from [dbo].[FeathersDonated] FD
join [dbo].[Couses] C on FD.corpid=3 and FD.[cousesid]=C.id
join [dbo].[Couses_lang] CL on FD.[cousesid]=CL.cousesid and
CL.language='en-US'
JOIN [dbo].[Organization_lang] COL on COL.orgid=2 and COL.language='en
US'
group by FD.cousesid,CL.[title],CL.[description],COL.title
i have tried the following set of code. please do help
var featherDonated = _GoUoW.FeathersDonated.FindBy(x => x.corpid ==
param.corpid)
.GroupBy(x => x.cousesid).Select(x => new { cousesid = x.Key, amount =
x.Select(a => a.amount).DefaultIfEmpty(0).Sum(), feathers = x.Select(a =>
a.feathers).DefaultIfEmpty(0).Sum() })
.Join(_GoUoW.Couses.GetAll(), feather => feather.cousesid, couse =>
couse.id, (feather, couse) => new { feather, couse })
.Join(_GoUoW.Organization_lang.FindBy(orglang => orglang.language == "en-
US"), couses => couses.couse.orgid, orgid => (param.organizationid > 0 ?
param.organizationid : orgid.orgid), (couses, orgid) => new { couses,
orgid
})
.Join(_GoUoW.Couses_lang.FindBy(couselang => couselang.language == "en-
US"),
organization => organization.orgid.orgid, couselang => couselang.cousesid,
(organization, couselang) => new { organization, couselang })
.Select(x => new
{
x.organization.couses.feather.amount,
x.organization.couses.feather.feathers,
x.couselang.title
//x.organization.orgid.title,
}).ToList();
I have two types producttype and accounttype inside product and account indices, and I need to construct a search query to hit both of them.
Right now I have ended up with the following query:
var searchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType), typeof(accountType)))
.Query(q => q
q.Nested(n => n
.Path(Infer.Field<ProductType>(ff => ff.Keywords))
.Query(nq => nq
.Match(t => t
.Field(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword))
.Query(query)
)
||
nq.Term(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword.Suffix("keyword")), query)
)
)
&&
+q.Term("_type", "producttype")
||
q.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<accountType>(ff => ff.AccountName, 1.5))
.Field(Infer.Field<accountType>(ff => ff.Description, 0.8))
)
.Operator(Operator.Or)
.Query(query)
) &&
+q.Term("_type", "accounttype")
)
);
When I run this query it doesn't work because of keywords nested object not found inside accounttype(but in my case I am filtering by _type so it should work).
So how can I filter by _index/_type when I have nested object inside one index?
Try by adding .IgnoreUnmapped(true) inside Nested object.
var searchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType), typeof(accountType)))
.Query(q => q
q.Nested(n => n
.IgnoreUnmapped(true)
.Path(Infer.Field<ProductType>(ff => ff.Keywords))
.Query(nq => nq
.Match(t => t
.Field(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword))
.Query(query)
)
||
nq.Term(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword.Suffix("keyword")), query)
)
)
&&
+q.Term("_type", "producttype")
||
q.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<accountType>(ff => ff.AccountName, 1.5))
.Field(Infer.Field<accountType>(ff => ff.Description, 0.8))
)
.Operator(Operator.Or)
.Query(query)
) &&
+q.Term("_type", "accounttype")
)
);
I want my "tag_post" table to be created in "article" schema but it's created in "public" schema.
List(x => x.Tags, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});
I have never used mapping by code, but i assume this is the solution:
List(x => x.Students, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
l.Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});
I have query in HQL which works good:
var x =_session.CreateQuery("SELECT r FROM NHFolder f JOIN f.DocumentComputedRights r WHERE f.Id = " + rightsHolder.Id + " AND r.OrganisationalUnit.Id=" + person.Id);
var right = x.UniqueResult<NHDocumentComputedRight>();
Basically I receive NHDocumentComputedRight instance.
I've tried to implement the same query in QueryOver. I did this:
var right = _session.QueryOver<NHFolder>().JoinAlias(b => b.DocumentComputedRights, () => cp).Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp).List<NHDocumentComputedRight>();
But I get null reference exception.
How can I implement this query in QueryOver?
Update (added mappings) - NHibernate 3.2:
public class FolderMapping: ClassMapping<NHFolder>
{
public FolderMapping()
{
Table("Folders");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
Set(x => x.DocumentComputedRights, v =>
{
v.Table("DocumentComputedRightsFolder");
v.Cascade(Cascade.All | Cascade.DeleteOrphans);
v.Fetch(CollectionFetchMode.Subselect);
v.Lazy(CollectionLazy.Lazy);
}, h => h.ManyToMany());
Version(x => x.Version, map => map.Generated(VersionGeneration.Never));
}
}
public class DocumentComputedRightMapping : ClassMapping<NHDocumentComputedRight>
{
public DocumentComputedRightMapping()
{
Table("DocumentComputedRights");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
ManyToOne(x => x.OrganisationalUnit, map =>
{
map.Column("OrganisationalUnit");
map.NotNullable(false);
map.Cascade(Cascade.None);
});
}
}
public class OrganisationUnitMapping : ClassMapping<NHOrganisationalUnit>
{
public OrganisationUnitMapping()
{
Table("OrganisationalUnits");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
}
}
Thanks
AFAIK criteria/queryOver can only return the entity it was created for (NHFolder in your example) or columns which are set to entity with aliastobean. you could do a correlated subquery instead.
var subquery = QueryOver.Of<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp.Id);
var right = _session.QueryOver<NHDocumentComputedRight>()
.WithSubquery.Where(r => r.Id).Eq(subquery)
.SingleOrDefault<NHDocumentComputedRight>();
I think you have a problem with the select statement, have you tried something like this:
var right = _session.QueryOver<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(x => x.DocumentComputedRights)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.List<NHDocumentComputedRight>();
This is what is working for me so it should work in you case as well.
I would guess that the main reason behind the problem is the lack of proper overload on the Select method. In reality you would like to write it like this:
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(() => cp)
but the Expression<Func<object>> is not there. Hopefully it's going to be included in the next version.
I have this mapping ( it comes from adventureworks since I used it in a demo app for an automatic paging collection )
ModelMapper mapper = new ModelMapper(new SimpleModelInspector());
mapper.Class<Contact>(
k => {
k.Id(i => i.ContactID, m => m.Generator(Generators.Native));
k.Schema("Person");
}
);
mapper.Class<Employee>(
k =>
{
k.Id(i => i.EmployeeID, m => m.Generator(Generators.Native));
k.Schema("HumanResources");
k.ManyToOne(c => c.Contact, m => m.Column("ContactID"));
}
);
mapper.Class<SalesOrderHeader>(
k =>
{
k.Id(i => i.SalesOrderID,m=>m.Generator(Generators.Native));
k.Schema("Sales");
k.ManyToOne(c => c.SalesPerson, m => m.Column("SalesPersonID"));
k.ManyToOne(c => c.Contact, m => m.Column("ContactID"));
}
);
var map = mapper.CompileMappingForAllExplicitlyAddedEntities();
cfg.AddDeserializedMapping(map,string.Empty);
and the following ( limited ) query:
var list = NHHelper.Instance.CurrentSession.Query<SalesOrderHeader>()
.Fetch(k => k.Contact)
.Fetch(k => k.SalesPerson)
.Skip(first)
.Take(count)
.ToList();
I can't remove the select N+1 caused by employee-contact, how can I do ?
Consider mapping too can be changed !
EDIT: I add the working solution by #cremor
var list = NHHelper.Instance.CurrentSession.Query<SalesOrderHeader>()
.Fetch(k => k.Contact)
.Fetch(k => k.SalesPerson).ThenFetch(k=>k.Contact)
.Skip(first)
.Take(count)
.ToList();
this will avoid the problem.
Adding .ThenFetch(c => c.Contact) after .Fetch(k => k.SalesPerson) should also fetch the Contact of the Employee.