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 fieldsFieldPath catalogFieldPath = new FieldPath( "ArticleType.CatalogProxy" );FieldPath eanFieldPath = new FieldPath( "ArticleType.Ean" );//search expressionEqualExpression 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 parametersSearchParameters searchParameters = new SearchParameters( DataSource.MASTER.getIdentifier(), "ArticleType", rootExpression );ExecuteSearchEx search = new ExecuteSearchEx( searchParameters );search.runWithCoreException( new NullProgressMonitor() );//search resultReportResult 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 fieldpathsField 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 );//expressionExpression 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 ) );//searchsearchParameters = new SearchParameters( DataSource.MASTER.getIdentifier(), "ArticleType", rootExpression );search = new ExecuteSearchEx( searchParameters );search.runWithCoreException( new NullProgressMonitor() );//search resultsearchResult = search.getReportResult();ReportResult assortmentReportResult //= ... create assortment reportEntityType 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 resultsearchResult = 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 resultsearchResult = 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 );