Hi I know most probably this query was asked. How can I improve query performance on Sitecore queries. I've installed dotTrancer and got the results you can see into this image. My method with I did not displayed in the image tooked 2,551 ms and Sitecore query toked 2,344 ms which is huge.
I am using Sitecore 7.2 i think their are around 10k item records into the database. We don't have more then 5 version per item. The query we do is:
return rootItem.Axes.SelectSingleItem(string.Format("descendant::*[##{0}='{1}']", attributeName, attributeValue));
attributeName = TemplateName.
Do you have any ideas how I can optimize the request?
Do not use Sitecore API for search. Use Sitecore Search:
public void Search(Item rootItem, string templateName)
{
var index = ContentSearchManager.GetIndex("sitecore_" + Sitecore.Context.Database.Name + "_index");
using (var context = index.CreateSearchContext())
{
var result = context.GetQueryable<SearchResultItem>().FirstOrDefault(i => i.TemplateName == templateName && i.Paths.Contains(rootItem.ID));
if (result != null)
{
Item resultItem = result.GetItem();
}
}
}
Related
I am applying search functionality in my system using Sitecore 7.0 (actually I am converting my code from Sitecore 6.5 to sitecore 7.0). When I try to get index using Sitecore.Search.SearchManager.GetIndex method, I find configuration property with null value.
My sample code in 6.5 is as below
webDb = Sitecore.Context.Database;
Sitecore.Data.Indexing.Index indx = webDb.Indexes["system"]; //Getting warning - deprecated method
Item bucketItem = Sitecore.Context.Item;
IndexSearcher indexSearcher = indx.GetSearcher(webDb);
topDocs = GetContent(keyWords, webDb, indexSearcher, year, regionName);
if (topDocs != null)
{
int totalMatchItemCount = topDocs.TotalHits;
if (totalMatchItemCount > 0)
{
returnValues = new Item[totalMatchItemCount];
int i = 0;
foreach (ScoreDoc scoreDoc in topDocs.ScoreDocs)
{
Document doc = indexSearcher.Doc(scoreDoc.Doc);
Item item = Index.GetItem(doc, webDb);//Getting warning - deprecated method
returnValues[i++] = item;
}
}
}
Its works fine but gives error of deprecated method on below lines,
Sitecore.Data.Indexing.Index indx = webDb.Indexes["system"];
and
Item item = Index.GetItem(doc, webDb);
My converted code of Sitecore 7.0 is as below,
var children = new List<Item>();
Sitecore.Search.Index searchIndx = Sitecore.Search.SearchManager.GetIndex("system");//Shows SearchManager._Configuration with NULL value, hence all methods and property getting with exception.
using (var searchContext = searchIndx.CreateSearchContext())
{
var ftQuery = new Sitecore.Search.FullTextQuery(keyWords);
var hits = searchContext.Search(ftQuery);
var results = hits.FetchResults(0, hits.Length);
foreach (Sitecore.Search.SearchResult result in results)
{
//My stuff
}
}
When I am trying to fetch value using Sitecore 7.0, get the below exception
Could not create instance of type: Lucene.Net.Analysis.Standard.StandardAnalyzer. No matching constructor was found.
Thanks.
I have a feeling this is because you're still using the pre-Sitecore 7 Sitecore.Search API rather than the newer Sitecore.ContentSearch.
Try this for some further help: Searching with the new Sitecore 7 API
Use below code to get index in Sitecore 7.
// Index
public static string IndexName
{
get
{
return (Sitecore.Context.Database.Name.ToLower()) == "master" ? "sitecore_master_index" : "sitecore_web_index";
}
}
public static ISearchIndex _index;
public static ISearchIndex Index
{
get
{
if (_index == null) { _index = ContentSearchManager.GetIndex(IndexName); }
return _index;
}
}
Could not create instance of type:
Lucene.Net.Analysis.Standard.StandardAnalyzer. No matching constructor
was found.
I've seen this error occur when there are DLLs from multiple Sitecore versions in your /bin folder, so I'd agree with #TwentyGotoTen: it sounds like you either missed out a step in the upgrade process, or you need to check your deploy process to make sure your solution isn't referencing older versions of Sitecore assemblies.
The database I am trying to pull data from has approximately 50,000 documents. Currently it takes around 90 seconds for an iOS or Android device to query and display the data to the mobile device in a view. My code is posted below. Is there something I could be doing differently to speed this up? Thanks for any tips.
function updateAllPoliciesTable() {
try {
var db = Alloy.Globals.dbPolicyInquiry;
var view = db.getView("AllRecordsByInsured");
var vec = view.getAllEntriesBySQL("Agent like ? OR MasterAgent like ?", [Ti.App.agentNumber, Ti.App.agentNumber], true);
var ve = vec.getFirstEntry();
var data = [];
while (ve) {
var unid = ve.getColumnValue("id");
var row = Ti.UI.createTableViewRow({
unid : unid,
height: '45dp',
rowData: ve.getColumnValue("Insured") + " " + ve.getColumnValue("PolicyNumber")
});
var viewLabel = Ti.UI.createLabel({
color : '#333',
font : {
fontSize : '16dp'
},
text: toTitleCase(ve.getColumnValue("Insured")) + " " + ve.getColumnValue("PolicyNumber"),
left: '10dp'
});
row.add(viewLabel);
data.push(row);
ve = vec.getNextEntry();
}
//Ti.API.log("# of policies= " + data.length);
if(data.length == 0) {
var row = Ti.UI.createTableViewRow({
title : "No policies found"
});
data.push(row);
}
$.AllPoliciesTable.setData(data);
Alloy.Globals.refreshAllPolicies = false;
Alloy.Globals.loading.hide();
} catch (e) {
DTG.exception("updateAllPoliciesTable -> ", e);
}
}
Create an index on the appropriate table, that should speed up things.
The SQLite table for your view should be named "view_AllRecordsByInsured".
Create an index for that table, check SQLite documentation about "CREATE INDEX" for more details.
To execute the appropriate SQL, you could use the DTGDatabase class like
var sqldb = new DTGDatabase(Alloy.Globals.dbPolicyInquiry.localdbname);
sqldb.execute("CREATE INDEX IF NOT EXISTS ON view_AllRecordsByInsured (Agent,MasterAgent)")
If that does give enough speed, look at full text search for SQLite dbs.
Here is some example code regarding full text indexes to give you a starting point:
CREATE VIRTUAL TABLE ft_view__mobile_companies_ USING fts4(id, customername, customercity)
INSERT INTO ft_view__mobile_companies_(id, customername, customercity) SELECT id, customername, customercity FROM view__mobile_companies_
To query the index you need to execute SQL with the MATCH operator (see SQLite documentation). In one app I have well over 100.000 datasets synchronized from a Domino view, and searching using a fulltext search in SQLite works instantly.
Well, unlike big database engines, the SQLite database engine is more limited, and so are the devices that it's run on.
What I would try to do is check the query that pulls the data - are you using indexes in your table? do you use them to query? is there unnecessary joins or pulls?
I you fail to tweet the query you should maybe consider checking out a mobile noSQL solution - I know there are some on the appcelerator marketplace - check if it suits your needs and if it speeds up things.
I have several document collections that occasionally need to be pulled together into a single index for reporting purposes.
This FAQ provides a solution for writing such an index in Raven Studio: http://ravendb.net/faq/indexing-across-entities
While I understand I won't get full compile-time checking, I'm trying to avoid completely unchecked code like this:
public class Assets_ById : AbstractIndexCreationTask
{
public override IndexDefinition CreateIndexDefinition()
{
return new IndexDefinition
{
Map = #"from doc in docs
where doc[""#metadata""][""Raven-Entity-Name""] == ""Cars"" ||
doc[""#metadata""][""Raven-Entity-Name""] == ""Trains"" ||
doc[""#metadata""][""Raven-Entity-Name""] == ""Boats"" ||
doc[""#metadata""][""Raven-Entity-Name""] == ""Planes""
select new
{
Cost = doc.Cost,
Id = doc.Id,
Name = doc.Name,
Type = doc.Type,
};"
}
}
}
Is there something similar to the generic AbstractIndexCreationTask<T> that will allow me to define a heterogeneous index with lambda expressions?
You can use WhereEntityIs(names), like this:
from doc in docs.WhereEntityIs<Vehicle>("Cars", "Trains", "Boats", "Planes")
select new
{
doc.Cost,
doc.Name,
doc.Type
}
Take a look here: https://groups.google.com/forum/#!topic/ravendb/9wvRY0OiGBs
It's basically the same question and the short answer is:
"right now there isn't a better option, but there will be in the future"
I am using NHibernate.Search libraries in my project for free text search. Recently when I started getting more than 2100 results, I started getting max parameter length error from SQL Server.
Does NHibernate.Search take care of such situation ? Any workaround anyone ?
You could modify NHibernate.Search code to take care of this, or, use custom paging, IE get number of hits for your search, then page nhibernate search results accordingly.
public IList<TEntity> Search<TEntity>(Query query, bool? active, string orderBy)
{
var search = NHibernate.Search.Search.CreateFullTextSession(this.session);
var total = search.CreateFullTextQuery(query, typeof(TEntity)).ResultSize;
var first = 0;
var l = new List<TEntity>();
while (total > 0)
{
l.AddRange(search.CreateFullTextQuery(query, typeof(TEntity))
.SetFirstResult(first)
.SetMaxResults(1000)
.List<TEntity>());
first += 1000;
total -= 1000;
}
return l;
}
See : IFullTextQuery - exception if there are too may objects
We're using Raven to validate logins so people can get into our site.
What we've found is that if you do this:
// Context is an IDocumentSession
Context.Query<UserModels>()
.SingleOrDefault(u => u.Email.ToLower() == email.ToLower());
The query only filters on the first 128 docs of the documents in
Raven. There are several thousand in our database, so unless your
email happens to be in that first 128 returned, you're out of luck.
None of the Raven samples code or any
sample code I've come across on the net performs any looping using
Skip() and Take() to iterate through the set.
Is this the desired behavior of Raven?
Is it the same behavior even if you use an advanced Lucene Query? ie; Do advanced queries behave any differently?
Is the solution below appropriate? Looks a little ugly. :P
My solution is to loop through the set of all documents until I
encounter a non null result, then I break and return .
public T SingleWithIndex(string indexName, Func<T, bool> where)
{
var pageIndex = 1;
const int pageSize = 1024;
RavenQueryStatistics stats;
var queryResults = Context.Query<T>(indexName)
.Statistics(out stats)
.Customize(x => x.WaitForNonStaleResults())
.Take(pageSize)
.Where(where).SingleOrDefault();
if (queryResults == null && stats.TotalResults > pageSize)
{
for (var i = 0; i < (stats.TotalResults / (pageIndex * pageSize)); i++)
{
queryResults = Context.Query<T>(indexName)
.Statistics(out stats)
.Customize(x => x.WaitForNonStaleResults())
.Skip(pageIndex * pageSize)
.Take(pageSize)
.Where(where).SingleOrDefault();
if (queryResults != null) break;
pageIndex++;
}
}
return queryResults;
}
EDIT:
Using the fix below is not passing query params to my RavenDB instance. Not sure why yet.
Context.Query<UserModels>()
.Where(u => u.Email == email)
.SingleOrDefault();
In the end I am using Advanced Lucene Syntax instead of linq queries and things are working as expected.
RavenDB does not understand SingleOrDefault, so it performs a query without the filter. Your condition is then executed on the result set, but per default Raven only returns the first 128 documents.
Instead, you have to call
Context.Query<UserModels>()
.Where(u => u.Email == email)
.SingleOrDefault();
so the filtering is done by RavenDB/Lucene.