I am beginner to Fluent Nhibernate. i have created one sample application in asp.net mvc 3 with Fluent Nhibernate. here is the code that i am using for initialisation.
private static void initialisationFactory()
{
try
{
_sessionFactory = Fluently.Configure() .Database(MsSqlConfiguration.MsSql2005.ConnectionString(#"Server=10.10.10.10;Database=Product_Demo;uid=sa;pwd=12345;Trusted_Connection=false;"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf< CompanyEntity >().ExportTo("d:\"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf< ModuleEntity>().ExportTo("d:\"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf< RoleEntity>().ExportTo("d:\"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf< UserEntity>().ExportTo("d:\"))
.ExposeConfiguration(cfg => new SchemaExport(cfg))
.BuildSessionFactory();
}
catch (Exception e)
{
throw;
}
}
Now is it necessory to add .Mapping..... lines for all tables? like below..
.Mappings(m => m.FluentMappings.AddFromAssemblyOf().ExportTo("d:\"))
And will it be increase memory of the project while running?
Thanks in advance.
You only need to do it once. Point it to where your entities are:
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Product>.ExportTo("d:\"))
where Product is a class in your project where all the rest of your classes are declared/included.
Related
I have two indices with the following configuration with mappings
var settings = new ConnectionSettings(new Uri("http://localhost:9200/"));
settings
.DefaultMappingFor<ManagementIndex>(m => m
.IndexName("management")
)
.DefaultMappingFor<PropertyIndex>(m => m
.IndexName("apartmentproperty")
);
var client = new ElasticClient(settings);
1) Properties mapping
client.Indices.Create("property", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Map<PropertyIndex>(map => map
.AutoMap()
.Properties(p => p
.Nested<PropertyData>(n => n
.Name(c => c.property)
.AutoMap()
.Properties(pp => pp
.Text(c => c
.Name(np => np.city)
.Analyzer("standard")
)
.Text(c => c
.Name(np => np.market)
.Fields(ff => ff
.Text(tt => tt
.Name(np => np.market)
.Analyzer("standard")
)
.Keyword(k => k
.Name("keyword")
.IgnoreAbove(256)
)
)
).Text(c => c
.Name(np => np.name)
.Analyzer("standard")
)
)
)
)
)
);
and
2) Owner
if (client.Indices.Exists("owner").Exists)
client.Indices.Delete("owner");
client.Indices.Create("owner", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Map<OwnerIndex>(map => map
.AutoMap()
.Properties(p => p
.Nested<OwnerProp>(n => n
.Name(c => c.owner)
.AutoMap()
.Properties(pp => pp
.Text(c => c
.Name(np => np.market)
.Fields(ff => ff
.Text(tt => tt
.Name(np => np.market)
.Analyzer("standard")
)
.Keyword(k => k
.Name("keyword")
.IgnoreAbove(256)
)
)
).Text(c => c
.Name(np => np.name)
.Analyzer("standard")
)
)
)
)
)
);
with the following POCO definitions
public class PropertyData
{
public string name { get; set; }
public string city { get; set; }
public string market { get; set; }
}
public class PropertyIndex
{
public PropertyData property { get; set; }
}
public class OwnerProp
{
public string name { get; set; }
public string market { get; set; }
}
public class OwnerIndex
{
public OwnerProp owner { get; set; }
}
Trying to do a search through the two indices like so
public async Task<object> SearchPropertiesAsync(string searchQuery, List<string> description, int limit = 25, int skip = 1)
{
var propertyfilters = new List<Func<QueryContainerDescriptor<object>, QueryContainer>>();
var ownerFilters = new List<Func<QueryContainerDescriptor<object>, QueryContainer>>();
if (description.Any())
{
propertyfilters.Add(fq => fq.Terms(t => t.Field("property.market.keyword").Terms(description)));
ownerFilters.Add(fq => fq.Terms(t => t.Field("owner.market.keyword").Terms(description)));
}
var searchResponse = await _elasticClient.SearchAsync<object>(s => s
.Index(Indices.Index(typeof(PropertyIndex)).And(typeof(OwnerIndex)))
.Query(q => (q
.Nested(n => n
.Path(Infer.Field<PropertyIndex>(ff => ff.property))
.Query(nq => nq
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<PropertyIndex>(ff => ff.property.city))
.Field(Infer.Field<PropertyIndex>(ff => ff.property.market))
.Field(Infer.Field<PropertyIndex>(ff => ff.property.name))
)
.Operator(Operator.Or)
.Query(searchQuery)
.Fuzziness(Fuzziness.Auto)
) && +q.Bool(bq => bq.Filter(propertyfilters))
))
) || (q
.Nested(n => n
.Path(Infer.Field<OwnerIndex>(ff => ff.mgmt))
.Query(nq => nq
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<OwnerIndex>(ff => ff.owner.market))
.Field(Infer.Field<OwnerIndex>(ff => ff.owner.name))
)
.Operator(Operator.Or)
.Query(searchQuery)
.Fuzziness(Fuzziness.Auto)
)
&& +q.Bool(bq => bq.Filter(ownerFilters))
))
)
).From((skip - 1) * limit)
.Size(limit)
);
return searchResponse.Documents;
}
calling the SearchPropertiesAsync method returns this error messages (truncated for brevity)
....
"index": "owner",
"caused_by": {
"type": "illegal_state_exception",
"reason": "[nested] failed to find nested object under path [property]"
}
....
"index": "property",
"caused_by": {
"type": "illegal_state_exception",
"reason": "[nested] failed to find nested object under path [owner]"
}
Notice that it looks like its trying to perform a nested search of owner. on property index and a nested search of property. on owner index which doesnt exist.
I feel like this should be a very trivial problem but I have been using ElasticSearch for only 4days now and still very new into it.
Is there something I am doing wrongly or is there something I am missing. Have searched the whole internet to even arrive at the solution I have at the moment.
Note that when you executed the nested query only one index at a time, the code works fine but trying to execute on multiple Indices is where my problem lies. Any help will be highly appreciated.
I am using ElasticSearch 7.3.2 and Nest Client 7.3.0.
I don't mind downgrading to a lower version that works.
Apparently, according to the docs
ignore_unmapped
(Optional, boolean) Indicates whether to ignore an unmapped path and not return any documents instead of an error. Defaults to false.
If false, Elasticsearch returns an error if the path is an unmapped field.
You can use this parameter to query multiple indices that may not contain the field path.
So chaining .IgnoreUnmapped(true) on the query body for each of the nested query solved the problem.
Just in case someone else encounter same problem
This was my code in the earlier version of ES it used to work. After moving to ES 5.5. It has stopped working and it gives a compiler error.
Error: 'QueryStringQueryDescriptor' does not contain a definition for 'OnFields' and no extension method 'OnFields' accepting a first argument of type 'QueryStringQueryDescriptor'
Below is my code snippet...
public List<EmployeeInfo> SearchText2(string query, List<string> sendersList, int page = 0, int pageSize = 50)
{
try
{
var result = this.client.Search<EmployeeInfo>(s => s
.From(page * pageSize)
.Size(int.MaxValue)
.Query(q => q
.QueryString(qs => qs.Query(query).UseDisMax()
.OnFields(b => b.Subject)
.OnFields(b => b.Body)
))
.SortDescending(f => f.ReceivedTime)
.Filter(f => f.Terms(ak => ak.SenderName, sendersList))
);
...
// Some code here
}
Any tips on how to make this work will be great.
In latest version of Nest library there are some API changes
Instead of OnFields in QueryString you should use Fields
QueryString(qs => qs.Query(string.Empty).UseDisMax()
.Fields(descriptor => descriptor.Fields(b => b.Subject, b => b.Body))
))
Instead of SortDescending you should use Sort
.Sort(descriptor => descriptor.Field(f => f.ReceivedTime, SortOrder.Descending))
Also the filters are not available in elasticsearch starting from version 5 and you should use bool query with filter
Query(descriptor =>
descriptor.Bool(boolQuery =>
boolQuery
.Must(query => query.MatchAll())
.Filter(f => f.Terms(ak => ak.SenderName, sendersList)
)
)
)
This is my class when inserting to ES
public class BasicDoc
{
public string Name { get; set; }
public string Url { get; set; }
}
I managed successfully insert my document to ES using NEST. But I'm having trouble to do a aggregation. My goals is to have something similar to SQL Group By. What I did so far:
var response = elastic.Search<BasicDoc>(s => s
.Aggregations(a => a
.Terms("group_by_url", st => st
.Field(o => o.Url)
))
);
I tried to aggregate my document based on BasicDoc.Url. Say I have these in my ES:
/api/call1/v1
/api/call2/v1
/api/call1/v1
When I debug, I my Nest.BucketAggregate will have 4 Items key which is api,call1, call2 and v1. I was expecting only 2 which are /api/call1/v1 and /api/call2/v1. What I'm doing wrong?
You currently have analysis set up on your Url property which means that it will be tokenized by the standard analyzer and terms stored in the inverted index. If you need to be able to search on Uri and also need to aggregate on it, then you may consider mapping it as a multi_field where one field mapping analyzes it and another does not. Here's an example index creation with mapping
client.CreateIndex("index-name", c => c
.Mappings(m => m
.Map<BasicDoc>(mm => mm
.AutoMap()
.Properties(p => p
.String(s => s
.Name(n => n.Url)
.Fields(f => f
.String(ss => ss
.Name("raw")
.NotAnalyzed()
)
)
)
)
)
)
);
When you perform your aggregation, you can now use the Uri raw field
var response = client.Search<BasicDoc>(s => s
.Size(0)
.Aggregations(a => a
.Terms("group_by_url", st => st
.Field(o => o.Url.Suffix("raw"))
)
)
);
I'm a newbie for elasticsearch and we are evaluate elasticsearch for our webstore. One important feature is the usage of synonyms. Unfortunately I'm not able to create a index with synonyms. Please can anybody help me how I can use the synonyms feature. I didn't find any sample for this feature and elasticsearch 2.xx. The goal should be if I search for Hills the entry of Royal will be find.
I use the following code:
private ElasticClient GetClient()
{
var node = new Uri(ES_URI);
var uri = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(uri).DefaultIndex("product");
var client = new ElasticClient(settings);
return client;
}
public void CreateSynonymIndex()
{
Product product = new Product()
{
Id = "2",
ProductName = "Royal",
Description = "Katzenfutter für Nierkranke"
};
var client = GetClient();
client.DeleteIndex("product");
var syn = new[] { "royal, hills => royal" };
ICreateIndexResponse respose = client.CreateIndex("product", c => c
.Mappings(mp => mp.Map<Product>(d => d.
Properties(p => p.String(n => n.Name(name => name.ProductName).Index(FieldIndexOption.Analyzed)))))
.Settings(s => s
.Analysis(an => an
.Tokenizers(at=>at.Pattern("synonymTokenizer",pa=>pa.Pattern("Test")))
.Analyzers(a=>a.Custom("synonymAnalyser",ca =>ca
.Tokenizer("synonymTokenizer")
.Filters(new List<string> { "synonym" })))
.TokenFilters(tf => tf
.Synonym("synonym", sy => sy.Synonyms(syn)
.Tokenizer("whitespace")
.IgnoreCase(true)))))
);
client.Index(product);
}
public void ES_Search()
{
var client = GetClient();
var response = client.Search<Product>(search => search
.Query(q => q.Bool(b => b
.Should(
// s => s.Match(m => m.Query("sometest").Field(f => f.ProductName).Boost(1.1)),
s => s.Match(m => m.Query("hills").Field(f => f.ProductName).Fuzziness(Fuzziness.EditDistance(1)))
))));
var response1 = client.Search<Product>(s => s.Query(q => q.Term(p => p.ProductName, "hills")));
}
Regards,
Dominik
You have created analyzer with synonyms, but you are not using it. You need to tell elasticsearch that ProductName field should use synonymAnalyser analyzer.
.Mappings(mp => mp.Map<Product>(d => d.
Properties(p => p.String(n => n
.Name(name => name.ProductName)
.Analyzer("synonymAnalyser")
.Index(FieldIndexOption.Analyzed)))))
I noticed few more things though:
remeber that document is not immediately available in elasticsearch after calling client.Index(..) method. It will take some miliseconds. Searching just right after indexing document, you may not find it. You can read more about it here
I don't know if you creat ElasticClient with default index, because you didn't share it. If not, you will have to specify it in your search calls e.g.
client.Search<Product>(s => s.Index("product")).
Hope that helps you.
I am using Entity Framework and have to query a "Project" property a lot, which has a lot of properties which have to be included in the query, making the query bloated:
var project = await this.ProjectRepository.GetRaw().Where(x => x.ID == id).Include(x => x.Leader).Include(x => x.Users).Include(x => x.Firm).FirstOrDefaultAsync();
Please not that GetRaw() returns a IQueryable
Is there a way to construct some helper method where the "include" portion is added, while I dynamically pass in the rest of the query?
something like that:
public async Task<List<Project>> GetProjects(query)
{
return this.ProjectRepository.GetRaw().Include(x => x.Leader).Include(x => x.Users).Include(x => x.Firm) + query;
}
usage something like that:
public ProjectController
{
public void Test()
{
var result = GetProjects.Where(x => x.ID == 0).FirstOrDefaultAsync();
}
}
I think it should look more like this:
public ObjectQuery<Project> GetProjects()
{
return this.ProjectRepository.GetRaw()
.Include(x => x.Leader)
.Include(x => x.Users)
.Include(x => x.Firm);
}
Usage would look like this then:
var result = GetProjects().Where(x => x.ID == 0).FirstOrDefaultAsync();
You can create the expression as parameter and return it as IQueryable<T> so it can be continued by another query.
public IQueryable<Project> GetProjects(Expression<Func<Project, bool> query)
{
return this.ProjectRepository.GetRaw()
.Include(x => x.Leader)
.Include(x => x.Users)
.Include(x => x.Firm)
.Where(query);
}
Usage.
var project = await GetProjects(x => x.ID == 0).FirstOrDefaultAsync();