Entity Search
Item search is used to find root entities which satisfy arbitrary conditions. Conditions are defined in runtime on root entity fields and sub-entities fields. Search result is a report which contains a list of found root entity ids (see reporting framework for more details) or an array of entity proxies Item search is in fact a generic API to reporting framework and can (and will) replace most of the named reports.
In HPM 5.3 item search implementation has been redesigned and can be safely used to perform complex search queries over large datasets. Search API is defined in com.heiler.ppm.search.core plugin and can be used platform wide.
Search expression
Search conditions are defined using boolean expressions and field operands. Search expression example using pseudo code:
(ArticleType.Ean = 9780321349606)
AND
( (ArticleLangType.DescriptionShort
not
contains
"myDescription"
)
OR
NOT
( ArticleType.LastModified >
"2012.12.12 13:14"
) )
Available conditions and operands can be found in java package com.heiler.ppm.search.core.expression
Search filters
ACL filter. By default search result contains only items for which current user has READ ACL permission.
Alive only filter. By default search results do not contain soft-deleted items
Arbitrary filter. You can provide report result to define subset of entries to search in. This may improve performance if a subset is small (usefull when searching in a predefined assortment)
Examples
HPM 6.0 API
Starting from HPM 6.0 please use SearchService interface instead of ExecuteSearchEx utility. Platform wide search instance can be obtained using EntitySearchComponent singleton. Consider IoC principal and pass the SearchService instance in constructor (or using setter) instead of calling EntitySearchComponent.getSearchService() every time you need a search service instance.
Starting from HPM 6.0 you can use SearchExpressionBuilder to reduce amount of the boiler-plate code used to create search expression. It provides a kind of internal DSL to build search expression. See java doc for more detail.
//repository fields
FieldPath catalogFieldPath =
new
FieldPath(
"ArticleType.CatalogProxy"
);
FieldPath eanFieldPath =
new
FieldPath(
"ArticleType.Ean"
);
//search expression
EqualExpression equalCatalogExpression =
new
EqualExpression(
new
FieldPathExpression( catalogFieldPath ),
new
ValueExpression(CatalogProxy.MASTER_CATALOG_PROXY ) );
EqualExpression equalEanExpression =
new
EqualExpression(
new
FieldPathExpression( eanFieldPath ),
new
ValueExpression(
"9783898426350"
) );
Expression rootExpression = equalCatalogExpression.and( equalEanExpression );
//search parameters
SearchParameters searchParameters =
new
SearchParameters( DataSource.MASTER.getIdentifier(),
"ArticleType"
,
rootExpression );
ExecuteSearchEx search =
new
ExecuteSearchEx( searchParameters );
search.runWithCoreException(
new
NullProgressMonitor() );
//search result
ReportResult searchResult = search.getReportResult();
EntityType genericDataEntityType = RepositoryUtils.getRepositoryEntityType(
"GenericDataEntityType"
);
Field classifierField = RepositoryUtils.getRepositoryField(
"GenericDataEntityType.Classifier"
);
FieldPath classifierFieldPath = RepositoryUtils.getFieldPath( classifierField );
EqualExpression equalClassifierExpression =
new
EqualExpression(
new
FieldPathExpression( classifierFieldPath ),
new
ValueExpression(
"ExportTemplate"
) );
searchParameters =
new
SearchParameters( DataSource.MAIN.getIdentifier(),
"GenericDataEntityType"
, equalClassifierExpression );
search =
new
ExecuteSearchEx( searchParameters );
search.runWithCoreException(
new
NullProgressMonitor() );
searchResult = search.getReportResult();
SearchParameters searchParameters =
new
SearchParameters( DataSource.MASTER.getIdentifier(),
"ArticleType"
,
rootExpression );
searchParameters.setRevisionFilter(
new
RevisionSearchFilter( RevisionTokenFactory.create(
100
) ) );
ExecuteSearchEx search =
new
ExecuteSearchEx( searchParameters );
search.runWithCoreException(
new
NullProgressMonitor() );
//repository fieldpaths
Field shortDescriptionField = RepositoryUtils.getRepositoryField(
"ArticleLang.DescriptionShort"
);
Field modificationDateField = RepositoryUtils.getRepositoryField(
"ArticleType.LastModified"
);
FieldPath shortDescriptionFieldPathEN = RepositoryUtils.getFieldPath( shortDescriptionField );
FieldPath lastModifiedFieldPath = RepositoryUtils.getFieldPath( modificationDateField );
shortDescriptionFieldPathEN.getEntityPath()
.setLogicalKeyValue(
"ArticleLangType.LK.Language"
, 9L );
//expression
Expression containsShortDescENExpression =
new
ContainsExpression(
new
FieldPathExpression( shortDescriptionFieldPathEN ),
new
ValueExpression(
"not available"
) );
GreaterExpression lastDayModificationExpression =
new
GreaterExpression(
new
FieldPathExpression( lastModifiedFieldPath ),
new
ValueExpression(
new
Timestamp( System.currentTimeMillis() -
86400000
) ) );
equalCatalogExpression =
new
EqualExpression(
new
FieldPathExpression( catalogFieldPath ),
new
ValueExpression( CatalogProxy.MASTER_CATALOG_PROXY ) );
Expression expression = equalCatalogExpression.and( containsShortDescENExpression.or( lastDayModificationExpression ) );
//search
searchParameters =
new
SearchParameters( DataSource.MASTER.getIdentifier(),
"ArticleType"
, rootExpression );
search =
new
ExecuteSearchEx( searchParameters );
search.runWithCoreException(
new
NullProgressMonitor() );
//search result
searchResult = search.getReportResult();
ReportResult assortmentReportResult
//= ... create assortment report
EntityType articleEntityType = RepositoryUtils.getRepositoryEntityType(
"ArticleType"
);
equalCatalogExpression =
new
EqualExpression(
new
FieldPathExpression( catalogFieldPath ),
new
ValueExpression( CatalogProxy.MASTER_CATALOG_PROXY ) );
searchParameters =
new
SearchParameters( DataSource.MASTER.getIdentifier(),
"ArticleType"
, rootExpression );
search =
new
ExecuteSearchEx( searchParameters, articleEntityType.getReportType(), ReportPurposes.TEMPORARY.toInt(),
assortmentReportResult );
search.runWithCoreException(
new
NullProgressMonitor() );
//search result
searchResult = search.getReportResult();
assortmentReportResult =
null
;
// = ... create report ...
articleEntityType = RepositoryUtils.getRepositoryEntityType(
"ArticleType"
);
Field articleInternalIdField = RepositoryUtils.getRepositoryField(
"ArticleType.Id"
);
FieldPath articleInternalIdFieldPath = RepositoryUtils.getFieldPath( articleInternalIdField );
equalCatalogExpression =
new
EqualExpression(
new
FieldPathExpression( catalogFieldPath ),
new
ValueExpression( CatalogProxy.MASTER_CATALOG_PROXY ) );
NotExpression idsNotInAssortmentExpression =
new
NotExpression(
new
InExpression(
new
FieldPathExpression( articleInternalIdFieldPath ),
new
ValueExpression( assortmentReportResult ) ) );
expression = equalCatalogExpression.and( idsNotInAssortmentExpression );
searchParameters =
new
SearchParameters( DataSource.MASTER.getIdentifier(),
"ArticleType"
, rootExpression );
search =
new
ExecuteSearchEx( searchParameters);
search.runWithCoreException(
new
NullProgressMonitor() );
//search result
searchResult = search.getReportResult();
Limitations
Search has some limitations.
Cross datasource search is not supported (i.e. you can't build a single query to search for master and supplier articles simultaneously).
Only root entities can be searched
Search operates on EntityType repository level and generic search on Entity level is not possible. However if some kind of entity classifier is defined then you can use it in search expression (see ExportTemplate Example).
Search is not public API so far. If you are using search api you have to implement junit test to check if results are correct. This is especially true if you are using complex expressions with different logical keys
Non-standard logical keys may not work in search expressions or deliver wrong results. Such logical keys are not field based i.e. they do not have 'Field Type' attribute in the repository.
Debug
In case of error or wrong search results you can trace the internal search query and search filter by enabling 'com.heiler.ppm.search.server.internal.service' log category in the server log4j.xml.
<category name=
"com.heiler.ppm.search.server"
>
<priority value=
"TRACE"
/>
</category>
HSQ - Heiler Search Query language
HSQ is a search expression language which can be used to define entity search queries in a textual form (similar to SQL but more domain model oriented). Since it is currently only used in the context of the Rest Service API, its syntax is described in REST Search Query Language.
You can use the HSQParser class to parse a hsq query and build a SearchExpression which can then be used with the SearchService.
...
ConvertUtils convertUtils = ConvertUtils.getInstance();
EntityProxyFactory entityProxyFactory = EntityManagementComponent.getEntityProxyFactory();
EntityManagerRegistry managerRegistry = EntityManagementComponent.getManagerRegistry();
PermissionService permissionService = EntityManagementComponent.getPermissionService();
EntityProxyParser proxyParser =
new
EntityProxyParser( convertUtils, entityProxyFactory, managerRegistry );
RepositoryService repositoryService = RepositoryComponent.getRepositoryService();
NavigationService navigationService = RepositoryComponent.getNavigationService();
EnumProviderRegistry enumProviderRegistry = EntityManagementComponent.getEnumProviderRegistry();
FieldParser fieldParser =
new
FieldParser( repositoryService, navigationService, convertUtils, enumProviderRegistry, proxyParser, permissionService );
HSQParser hsqParser =
new
HSQParser( fieldParser, convertUtils );
String hsq =
"Article.EAN in (\"123456789\", \"987654321\", \"abcdefghij\") AND not (Article.Identifier = \"abc\" OR Article.Identifier equals \"xyz\")"
;
Expression expression = hsqParser.parseSearchQuery( hsq );
SearchParameters searchParameters =
new
SearchParameters( dataSource.getIdentifier(), entityType.getIdentifier(), expression );
searchParameters.setRevisionFilter(
new
RevisionSearchFilter( revisionToken ) );
SearchService searchService = EntitySearchComponent.getSearchService();
ReportResult reportResult = searchService.searchAsReport( progressMonitor, searchParameters, reportResultFilter );