I tried following in Lucene 6.2.1:
I have different fields A,B,C,D,E and I make for every field a different searchquery.
Then I want to make a intersection. Show it, when the result is everywhere true.
Someone told me to try this with Booleanquery. So this is my approach:
IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(index)));
IndexSearcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer();
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
QueryParser parser1 = new QueryParser("A", analyzer);// i have 5 different QueryParser
Query qPersonen = parser1.parse("searchstring"); // i have also 5 Queries
booleanQuery.add(qPersonen, BooleanClause.Occur.MUST);
TotalHitCountCollector collector = new TotalHitCountCollector();
TopDocs results = searcher.search(booleanQuery.build(), 100);
ScoreDoc[] hits = results.scoreDocs;
int numTotalHits = results.totalHits;
System.out.println("Results: " + numTotalHits);
Why isn't it working? What could be the fault? It always returns no results :(
As I see your code, It seems that you didn't get instance of BooleanQuery. Since lucene 5, the boolean query's API has been changed. Try the following:
QueryParser parser1 = new QueryParser("A", analyzer);// i have 5 different QueryParser
Query qPersonen = parser1.parse("searchstring"); // i have also 5 Queries
BooleanQuery.Builder bq = new BooleanQuery.Builder();
bq.add(new BooleanClause(aPersonen, BooleanClause.Occur.MUST));
Hope this will work for you :)
Related
I've got what is probably a simple issue, but cant seem to find an answer to it.
I have a custom record, with an list field containing the item records in the account.
Whenever I run the script it returns the 2 rows in the custom record, rather than the specific record im trying to source.
I know its list is just the items list, but when i try '10' as the internal id of the specific item record it throws an error.
nlobjSearchFilter('custrecord_pm_int_inventory_item',null,'is','10');
it throws an error, i have seen similar posts on stackoverflow for this, but not exactly trying to load a custom record that has a list field of item
// if inventory item has been found, check to see if it exists in the item tracking record
var filt = [];
filt[0] = new nlobjSearchFilter('custrecord_tc_int_inventory_item',null,'is','88999 shipping');
var cols = [];
cols[0] = new nlobjSearchColumn('internalid');
cols[1] = new nlobjSearchColumn('custrecord_tc_int_inventory_item');
var search = nlapiSearchRecord('customrecord_tc_int_item_tracking',null,filt,cols);
Hopefully im just missing something simple, but i cant seem to load the record, any ideas greatly appreciated
You gotta use anyof operator and pass an array, here's how it should look:
// if inventory item has been found, check to see if it exists in the item tracking record
var filt = [];
filt[0] = new nlobjSearchFilter('custrecord_tc_int_inventory_item',null,'anyof',['10']);
var cols = [];
cols[0] = new nlobjSearchColumn('internalid');
cols[1] = new nlobjSearchColumn('custrecord_tc_int_inventory_item');
var search = nlapiSearchRecord('customrecord_tc_int_item_tracking',null,filt,cols);
I am exploring the "QueryExpression" mechanism used to Retrieve data via the Dynamics CRM SDK, and I think I have hit a problem / limitiation with the SDK, but I would like to ascertain that for certain..
Given this desired SQL:
Select C.firstname, C.lastname
FROM contact C
INNER JOIN customeraddress A on C.contactid = A.parentid
WHERE
((C.firstname = 'Max' AND C.lastname = 'Planck') OR (C.firstname = 'Albert' AND C.lastname = 'Einstein'))
OR
A.Line1 = 'The secret moonbase'
I cannot appear to translate the filter criteria above (the where clause) into the equivalent SDK conditions / filterexpressions etc.
As you can see, I want to query:-
contact, joined to customeraddress (thats simple, just add a link entity to the query expression),
where the contact is either Albert Einstein, or Max Planck (Again, that is simple, add FilterExpressions to the QueryExpression)
OR the customeraddress 'line1' equals 'the secret moonbase' (This is the problematic bit, as soon as I append filter criteria to the LinkEntity, Dynamics uses an "AND" conjunction with the criteria / filters on the main entity.
So the problem I have described in point 3 above, means I can't query dynamics for:
(Albert Einstein Or Max Planck) or anyone who lives at the secret moonbase.
Is this is a current limtation of the SDK?
Ok, I have discovered the answer to this, thanks in part to #mwrichardsone who prompted me to explore how the Dynamics Crm Linq query provider does it, I was then able to work backwards from there..
So here is the equivalent Linq query expression which works (I am using the CrmOrganisationServiceContext):-
var contactsQuery = from c in orgService.CreateQuery("contact")
join a in orgService.CreateQuery("customeraddress") on (Guid)c["contactid"] equals (Guid)a["parentid"]
where (((string)c["firstname"] == "Max" && (string)c["lastname"] == "Planck")
|| ((string)c["firstname"] == "Albert" && (string)c["lastname"] == "Einstein"))
|| (string)a["line1"] == "The secret moonbase"
select c;
I then found this article which explains how you can convert linq query to a Query Expression or Fetch Xml: http://pogo69.wordpress.com/2012/04/05/crm-linq-provider-converting-expressions-to-queryexpression-andor-fetchxml/
Once i applied that technique I was able to see what the equivalent QueryExpression looks like.. and basically, the bit that I was missing (key insight) is that when you add a ConditionExpression you can set it's "EntityName". This means you can add a ConditionExpression to a filter group thats on the parent / main entity, even though the condition is actually for an attribute thats present on a link entity (in this case customeraddrress line1). I was assuming you had to add the condition to the linkentity that had that particular attribute - which is also what #Henk van Boeijen did in his answer - and that did not give the correct results.
So the final working QueryExpression looks like this (notice the condition for address line 1 is not added to the address link entity, its added to the filter group on the main entity, and it has an "entity name" set to the alias of the link entity)
var orgService = serviceProvider.GetOrganisationService();
using (orgService as IDisposable)
{
var query = new QueryExpression("contact");
query.ColumnSet.AddColumn("firstname");
query.ColumnSet.AddColumn("lastname");
// so link in customer address.
query.AddLink("customeraddress", "contactid", "parentid", JoinOperator.Inner);
var addressLink = query.LinkEntities[0];
addressLink.EntityAlias = "A";
addressLink.IncludeAllColumns();
// conditions for max planck
var firstName1Condition = new ConditionExpression("firstname", ConditionOperator.Equal, "Max");
var lastname1Condition = new ConditionExpression("lastname", ConditionOperator.Equal, "Planck");
// Groups those conditions using an "AND" conjunction.
var maxPlankFilter = new FilterExpression(LogicalOperator.And);
maxPlankFilter.AddCondition(firstName1Condition);
maxPlankFilter.AddCondition(lastname1Condition);
// conditions for albert einstein
var firstname2Condition = new ConditionExpression("firstname", ConditionOperator.Equal, "Albert");
var lastname2Condition = new ConditionExpression("lastname", ConditionOperator.Equal, "Einstein");
// Groups those conditions using an "AND" conjunction.
var albertEinsteinFilter = new FilterExpression(LogicalOperator.And);
albertEinsteinFilter.AddCondition(firstname2Condition);
albertEinsteinFilter.AddCondition(lastname2Condition);
// could optionally chain the 2 filters so we get Albert's contitions chained (using AND) to max's conditions
// albertEinsteinFilter.AddFilter(maxPlankFilter);
// conditions for address line 1 moonbase
var addressLine1Filter = new FilterExpression(LogicalOperator.And);
var line1Condition = new ConditionExpression("A", "line1", ConditionOperator.Equal, "The secret moonbase");
addressLine1Filter.AddCondition(line1Condition);
// add filters to query
// ensures each filter that we add to our queries criteria is chained together using an OR.
query.Criteria.FilterOperator = LogicalOperator.Or;
query.Criteria.AddFilter(albertEinsteinFilter);
query.Criteria.AddFilter(maxPlankFilter);
query.Criteria.AddFilter(addressLine1Filter);
var results = orgService.RetrieveMultiple(query);
int resultCount = 0;
foreach (var r in results.Entities)
{
resultCount++;
Console.WriteLine(string.Format("{0} {1} {2}", (string)r["firstname"], (string)r["lastname"], (string)((AliasedValue)r["A.line1"]).Value));
}
Console.WriteLine("There were " + resultCount + " results..");
}
Side Note: See #Henk van Boeijen's post below if you would like to see a shorter syntax for building a query expression. If productivity is truly your concern however, I would have to echo the comment from #Nicknow below and suggest that you seriously take a look at using the Linq query mechanism for performing CRM queries.
Also #Henk van Boeijen has pointed out that my answer is based on a feature that only appears in the 2013 SDK, and doesn't appear to be in prior versions. I haven't checked this personally, but that information is probably very useful for you to know especially if you are not using the latest versions of the SDK.
It is actually pretty straightforward; use the LogicalOperator and the LinkEntity.
I would recommend adding the DISTINCT predicate.
private IEnumerable<Entity> QueryExpression(IOrganizationService service)
{
var query = new QueryExpression("contact");
query.Distinct = true;
query.ColumnSet.AddColumns("firstname", "lastname");
query.Criteria.FilterOperator = LogicalOperator.Or;
var f1 = query.Criteria.AddFilter(LogicalOperator.And);
f1.AddCondition("firstname", ConditionOperator.Equal, "Max");
f1.AddCondition("lastname", ConditionOperator.Equal, "Planck");
var f2 = query.Criteria.AddFilter(LogicalOperator.And);
f2.AddCondition("firstname", ConditionOperator.Equal, "Albert");
f2.AddCondition("lastname", ConditionOperator.Equal, "Einstein");
var link = query.AddLink("customeraddress", "contactid", "parentid");
link.EntityAlias = "ca";
query.Criteria.AddCondition("ca", "line1", ConditionOperator.Equal, "The secret moonbase");
var response = service.RetrieveMultiple(query);
return response.Entities;
}
It is important to note that this query uses a new feature added in Dynamics CRM 2013. It does not work in Dynamics CRM 2011, because in that version it is not possible to specify an entityname (or its alias) in the ConditionExpression.
Recently I've started using Apache CMIS and read the official documentation and examples. I haven't noticed anything about paging query results.
There is an example showing how to list folder items, setting maxItemsPerPage using operationContext, but it seems that operationContext can be used inside getChilder method:
int maxItemsPerPage = 5;
int skipCount = 10;
CmisObject object = session.getObject(session.createObjectId(folderId));
Folder folder = (Folder) object;
OperationContext operationContext = session.createOperationContext();
operationContext.setMaxItemsPerPage(maxItemsPerPage);
ItemIterable<CmisObject> children = folder.getChildren(operationContext);
ItemIterable<CmisObject> page = children.skipTo(skipCount).getPage();
This is ok when it comes to listing u folder. But my case is about getting results from custom search query. The basic approach is:
String myType = "my:documentType";
ObjectType type = session.getTypeDefinition(myType);
PropertyDefinition<?> objectIdPropDef = type.getPropertyDefinitions().get(PropertyIds.OBJECT_ID);
String objectIdQueryName = objectIdPropDef.getQueryName();
String queryString = "SELECT " + objectIdQueryName + " FROM " + type.getQueryName();
ItemIterable<QueryResult> results = session.query(queryString, false);
for (QueryResult qResult : results) {
String objectId = qResult.getPropertyValueByQueryName(objectIdQueryName);
Document doc = (Document) session.getObject(session.createObjectId(objectId));
}
This approach will retrieve all documents in a queryResult, but I would like to include startIndex and limit. The idea would be to type something like this:
ItemIterable<QueryResult> results = session.query(queryString, false).skipTo(startIndex).getPage(limit);
I'm not sure about this part: getPage(limit). Is this right approach for paging? Also I would like to retrieve Total Number of Items, so I could know how to set up the max items in grid where my items will be shown. There is a method, but something strange is written in docs, like sometimes the repository can't be aware of max items. This is that method:
results.getTotalNumItems();
I have tried something like:
SELECT COUNT(*)...
but that didn't do the trick :)
Please, could you give me some advice how to do a proper paging from a query result?
Thanks in advance.
Query returns the same ItemIterable that getChildren returns, so you can page a result set returned by a query just like you can page a result set returned by getChildren.
Suppose you have a result page that shows 20 items on the page. Consider this snippet which I am running in the Groovy Console in the OpenCMIS Workbench against a folder with 149 files named testN.txt:
int PAGE_NUM = 1
int PAGE_SIZE = 20
String queryString = "SELECT cmis:name FROM cmis:document where cmis:name like 'test%.txt'"
ItemIterable<QueryResult> results = session.query(queryString, false, operationContext).skipTo(PAGE_NUM * PAGE_SIZE).getPage(PAGE_SIZE)
println "Total items:" + results.getTotalNumItems()
for (QueryResult result : results) {
println result.getPropertyValueByQueryName("cmis:name")
}
println results.getHasMoreItems()
When you run it with PAGE_NUM = 1, you'll get 20 results and the last println statement will return true. Also note that the first println will print 149, the total number of documents that match the search query, but as you point out, not all servers know how to return that.
If you re-run this with PAGE_NUM = 7, you'll get 9 results and the last println returns false because you are at the end of the list.
If you want to see a working search page that leverages OpenCMIS and plain servlets and JSP pages, take a look at the SearchServlet class in The Blend, a sample web app that comes with the book CMIS & Apache Chemistry in Action.
there are 7000 items in my list. i need to filter the list and retrieve result
i am using the following code in my webpart.
string query = "<Where><BeginsWith><FieldRef Name='Project' /><Value Type='Text'>ab</Value></BeginsWith></Where>"
SPQuery spquery = new SPQuery();
spquery.Query = query;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError)
as i am using ContentIterator still it is giving me the error "The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator"
Update:
string query2 = #"<Where><Eq><FieldRef Name='Project' /><Value Type='Text'>11759</Value></Eq></Where>";
SPQuery spquery = new SPQuery();
spquery.RowLimit = 10;
spquery.Query = query2;
spquery.QueryThrottleMode = SPQueryThrottleOption.Override;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError);
In every case weather I used SPCollectionItem or Iterator. when ever I am passing the where condition in spquery. same error comes.
To efficiently use ContentIterator and avoid throttle exception, you should explicitly include OrderBy clauses.
Try to use ContentIterator.ItemEnumerationOrderByNVPField which actually enables the index to be used.
For more details,check this out
http://extreme-sharepoint.com/2012/07/17/data-access-via-caml-queries/
Likely because the the Field you are comparing on is not indexed: http://msdn.microsoft.com/en-us/library/ff798465
If you were to build a query that returns the first 100 items sorted
by the ID field, the query would execute without issue because the ID
column is always indexed. However, if you were to build a query that
returns the first 100 items sorted by a non-indexed Title field, the
query would have to scan all 10,000 rows in the content database in
order to determine the sort order by title before returning the first
100 items. Because of this, the query would be throttled, and rightly
so—this is a resource-intensive operation.
You either have to ...
... set a RowLimit below the configured threshold on your query.
... or define a query that returns less items.
... or change the threshold of the list.
have you seen this:
msdn link
hmmz, just tried this and it still gave an error. If I use this however I can iterate over way more than 7k listitems:
private int GetItems(SPList list){
var query = new SPQuery();
query.Query = "";
query.QueryThrottleMode = SPQueryThrottleOption.Override;
var items = list.GetItems(query);
return items.Count;
}
so my advice is to just use the list.getitems
You just need to change your query.
//Keep your query inside <View></View> tag.
string query = "<View><Where><BeginsWith><FieldRef Name='Project' /><Value Type='Text'>ab</Value></BeginsWith></Where><View>"
SPQuery spquery = new SPQuery();
spquery.Query = query;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError)
Now run the program and it will work.
Yet another newbie SubSonic/ActiveRecord question. Suppose I want to insert a couple of records, currently I'm doing this:
using (var scope = new System.Transactions.TransactionScope())
{
// Insert company
company c = new company();
c.name = "ACME";
c.Save();
// Insert some options
company_option o = new company_option();
o.name = "ColorScheme";
o.value = "Red";
o.company_id = c.company_id;
o.Save();
o = new company_option();
o.name = "PreferredMode";
o.value = "Fast";
o.company_id = c.company_id;
o.Save();
scope.Complete();
}
Stepping through this code however, each of the company/company_option constructors go off and create a new myappDB object which just seems wasteful.
Is this the recommended approach or should I be trying to re-use a single DB object - and if so, what's the easiest way to do this?
I believe you can use the same object if you want to by setting its IsNew property to true, then change its data properties, save it again, repeat. Easy enough.
I 'm not so sure that you should bother, though. It depends on how bad those constructors are hurting you.
In my eyes assigning multiple objects to a single var is never a good idea but thats arguable. I would do this:
// Insert some options
company_option o1 = new company_option();
o1.name = "ColorScheme";
o1.value = "Red";
o1.company_id = c.company_id;
o1.Save();
company_option o2 = new company_option();
o2.name = "PreferredMode";
o2.value = "Fast";
o2.company_id = c.company_id;
o2.Save();
I you are worried about performance, that shouldn't be a issue unless you want to insert or update many objects at once. And again, in this case the time used for inserting the data takes longer than for the object creation.
If you are worried about performance you can skip the object creation and saving part completly by using a Insert query:
http://www.subsonicproject.com/docs/Linq_Inserts
db.Insert.Into<company_option>(
x => x.name,
x => x.value,
x => x.company_id)
.Values(
"ColorScheme",
"Red",
c.company_id
).Execute();