基础知识
该FlexibleSearch是内置采用hybris Commerce Suite的一个强大的检索语言。它能采用hybris商务套件使用基于SQL语法搜索类型和物品。
一个FlexibleSearch语句的执行发生在两个阶段:
pre-parsing(预解析)到一个SQL-compliant语句中和运行这个语句在数据库上
在预解析阶段,FlexibleSearch框架解析FlexibleSearch语法到SQL-compliant里。下面的两个代码段表现出一个FlexibleSearch查询和这个FlexibleSearch语句查询的结果,这是在数据库上执行的语句:
FlexibleSearch查询语句:
elect {pk}, {code}, {name[de]} from {Product}在数据库上执行的SQL语句:
SELECT item_t0.PK , item_t0.Code , lp_t0.p_name FROM products item_t0 JOIN productslp lp_t0 ON item_t0.PK = lp_t0.ITEMPK AND lp_t0.LANGPK= 9013632135395968 WHERE (item_t0.TypePkString IN ( 23087380955301264 , 23087380955663520 , 23087380955662768 , 23087380955661760 , 23087385363574432 , 23087380955568768 , 23087380955206016 ) )
该FlexibleSearch采用hybris Commerce Suite的类型系统从实际的数据库表这样你就可以在类型相同级别运行查询。不同于常规的SQL语句,在一个FlexibleSearch查询中您不必指定明确的数据库表名。该FlexibleSearch框架解析类型和数据库表自动依赖关系并指定必要UNIONS和JOINS在哪里。类型系统和数据库表示之间的整个转换过程是自动进行的。要访问一个类型中FlexibleSearch查询,请用花括号{and},如类型代码:
SELECT * FROM {Product}
采用hybris Commerce Suite的在某一用户帐户的上下文中执行FlexibleSearch查询,使用一个会话。因为不同的用户帐户访问在采用hybris商务套件的不同项目,搜索结果的数量取决于用户的帐户。搜索结果的数目被按类型的访问权限定义(这些仅影响采用hybris管理控制台的搜索结果),限制,目录版本和类别。
更多的特权用户帐户是,在更多的搜索结果FlexibleSearch产量在用户帐户的上下文中。默认情况下,分配给会话的用户帐户是匿名的,所以任何FlexibleSearch查询返回的搜索结果相匹配的默认匿名帐户。
匿名不同用户帐户的情况下运行从FlexibleSearch查询,该会话需要被分配给不同的用户帐户,如:
import de.hybris.platform.servicelayer.user.UserService; ... // Injected by Spring userService.setCurrentUser(userService.getUserForUID("myUserAccount")); ...
语法概要
FlexibleSearch查询的基本语法如下:
SELECT <selects> FROM <types> ( WHERE <conditions> )? ( ORDER BY <order> )?一个FlexibleSearch查询包括:
强制性的<selects>参数对SELECT子句。
强制性的<type>参数为对FROM子句。
强制性的一个可选的<conditions>字段的WHERE子句。
一个可选的ORDER BY子句。
SQL Command / Keyword | Description / Comment | Code Example |
ORDER BY {alias:attribute} | Display results ordered by the value of attribute. | SELECT ... FROM ... ORDER BY... |
ASC | 排序结果以升序 (a...z, 0...9). | SELECT ... FROM ... ORDER BY ... ASC |
DESC | 排序结果以降序(z...a, 9...0). | SELECT ... FROM ... ORDER BY ... DESC |
DISTINCT | Eliminates double entries in the query result. | SELECT DISTINCT ... FROM ... |
OR | Performs a logical OR compare between two queries. | ... WHERE ... OR ... |
AND | Performs a logical AND compare between two queries. | ... WHERE ... AND ... |
IS [NOT] NULL | Returns the results that are [not] null | ... WHERE ... IS [NOT] NULL |
[NOT] IN | Returns the results that are [not] part of the following statement ... WHERE ... [NOT] IN ... | |
[NOT] EXISTS | Returns the results that are [not] matching a given subquery. | ...WHERE ... EXISTS ( {{ SELECT ... }} ) |
LIKE | Compares to a pattern. | ... WHERE ... LIKE '...' |
% | Wildcard matching any number of characters. | ... WHERE ... LIKE '%...'||'...%...'||'...%' |
_ | Wildcard matching a single character. | ... WHERE ... LIKE '...' || '......' ||'..._' |
LEFT JOIN ON | Merges two tables into one. | ... LEFT JOIN ... ON ... = ... |
= | True if results are equal. | |
!=, <> | True if results are not equal. | |
< | True if result 1 is less than result 2. | |
<= | True if result 1 is equal to or less than result 2. | |
> | True if result 1 is greater than result 2. | |
>= | True if result 1 is equal to or greater than result 2. | |
CONCAT | 连接两个结果 - 在右边侧的例子将返回字符串结果。 | CONCAT ( 'resul', 't' ) |
:o | 外连接参数用于包括与在ProductsLP表(=. 表包含本地化产品)以及缺少行匹配结果否则,例如查询将只返回产品 与ProductsLP表中现有行,因为它只会使用JOIN。 | SELECT {p:PK} FROM {Product AS p} WHERE {p:description[en]:o} LIKE '%text%' OR {p:description[de]:o} LIKE '%text%' |
在<selects>字段中的值指定要返回的数据库列。星号(*)将返回所有数据库列,如SQL约定。要搜索一个属性,指定大括号,如属性标识符:SELECT{code}FROM {Product}。
要获取本地化的属性值,使用的语言标识符作为后缀属性名在,包含在方括号([and]),如:
SELECT * FROM {Category}这个查询返回每个数据库列的Category表。
SELECT {pk},{code},{name[de]} FROM {Product}
从产品表查询返回的数据库pk,code,name[de]列.
<type>
该数值为<type>在FROM子句中字段中指定采用hybris Commerce Suite的类型,嵌套在大括号{and}这是要搜索,例如:
SELECT * FROM {Product} SELECT * FROM {Category JOIN Catalog}
你可以指定一个别名用于区分属性字段,使用AS运算符:
SELECT {p.code} FROM {Product AS p} ORDER BY {p.code}
您也可以运行JOIN和LEFT JOIN的查询,如:
SELECT {cj.code} FROM {SyncItemCronJob AS sicj JOIN SyncItemJob AS sij ON {sicj:job} = {sij:pk} } SELECT {p1.PK},{p2.PK} FROM {Product AS p1 LEFT JOIN Product AS p2 ON {p1.code} = {p2.code} } WHERE {p1.PK} <> {p2.PK} ORDER BY {p1.code} ASC
一定要记住,这是最重要的,整个<type>块必须由封闭{和}不管多种类型.不要试图在多个放<type>块在FROM子句中。尽管这看起来是工作,它可能会导致不可预知的错误。
子类型
默认情况下,指定类型搜索导致FlexibleSearch查询来搜索该类型和任何子类型。例如,下面的代码片段返回codes和PKs所有实例的Product与VariantProduct
SELECT {code},{pk} FROM {Product}
通过增加一个尾部的感叹号(!),在FlexibleSearch查询仅搜索指定类型和忽略所有subtypes,下面的代码片段搜索Product的唯一实例不是VariantProduct,:
SELECT {code},{pk} FROM {Product!}
当搜索子类型所述FlexibleSearch首先检索字类型进行搜索,例如在Product的情况下,类型搜索是Product和VariantProduct。正如商务部的hybris一套房类型定义为一个项目,因此有一个主键(PK),在FlexibleSearch检索所有类型的PK进行搜索。搜索类型的PKs的清单放入IN子句WHERE子句内。
FlexibleSearch Query | SQL Statement |
SELECT {p:code}, {p:pk} | SELECT item_t0.Code , item_t0.PK FROM products item_t0 WHERE (item_t0.TypePkString IN ( 23087380955301264 , 23087380955663520 , 23087380955662768 , 23087380955661760 , 23087385363574432 , 23087380955568768 , 23087380955206016 ) ) |
SELECT {p:code}, {p:pk} | SELECT item_t0.Code , item_t0.PK FROM products item_t0 WHERE (item_t0.TypePkString = 23087380955206016 ) |
从搜索的类型中排除
如果你想确保某些类型从FlexibleSearch查询运行省略,有两种方法在您的处置:
使用请将ItemType操作员和一个参数.这种方法是可行的,如果你可以准备,并通过一个Map,引用要排除作为FlexibleSearch参数,如类型:
final Set<ComposedTypeModel> excludedTypes = new HashSet<ComposedTypeModel>(); excludedTypes.add(getComposedType("mySuborderType")); StringBuilder queryString = new StringBuilder("SELECT {").append(OrderModel.PK).append("} "); queryString.append("FROM {").append(OrderModel._TYPECODE).append("} "); queryString.append("WHERE {").append(OrderModel.ITEMTYPE).append("} NOT IN (?excluded)"); final FlexibleSearchQuery query = new FlexibleSearchQuery(queryString.toString(), Collections.singletonMap("excluded", excludedTypes));
使用JOIN子句.这种方法是可行的,如果你不能传递参数,例如,因为你需要直接输入FlexibleSearch声明:
SELECT {o.PK} FROM {Order AS o JOIN ComposedType AS t ON {o.itemtype}={t.PK} }WHERE {t.code} NOT IN ('Foo','Bar')
避免空间搜索条件条款 一定要避免空间的开始和结束搜索条件来看,随着因为= 'al' 和= 'al '是不相同的搜索条件,导致不同的搜索结果。
SELECT * FROM {Product} WHERE {code} LIKE '%al%'
使用常见的SQL布尔操作符(AND,OR)可以连接条件,如:
SELECT * FROM {Product} WHERE {code} LIKE '%al%' AND {code} LIKE '%15%'
使用IS NULL操作员发现,没有价值的所有条目:
SELECT * FROM {Product} WHERE {code} IS NULL
使用SQL布尔运算符NOT否定的情况是可能的:
SELECT * FROM {Product} WHERE {code} NOT LIKE '%al%'
它有可能组合否定和连接条件:
SELECT * FROM {Product} WHERE {code} LIKE '%al%' AND {code} NOT LIKE '%15%'
否定IS NULL运算符是不为空:
SELECT * FROM {Product} WHERE {code} IS NOT NULL
WHERE子句还允许子选择使用双花括号({{and}}),如:
SELECT {cat:pk} FROM {Category AS cat} WHERE NOT EXISTS ( {{ SELECT * FROM {CategoryCategoryRelation} WHERE {target}={cat:pk} }} /* Sub-select */ )
下面FlexibleSearch查询按照code数据库列的值,按降序排列的搜索结果:
SELECT {code},{pk} FROM {Product} ORDER BY {code} DESC
下面FlexibleSearch查询按照代码数据库列的值的搜索结果,按升序排列:(ASC是默认顺序):
SELECT {code},{pk} FROM {Product} ORDER BY {code}
参数
一个FlexibleSearch查询包含可选参数,标有前缀问号。参数,使您能够传递值到FlexibleSearch查询。例如,在下面的代码片段,参数Product可用于传递一个搜索模式:
SELECT {p:pk} FROM {Product AS p} WHERE {p:code} LIKE ?product
下面FlexibleSearch查询有两个参数,的startDate和结束日期:
SELECT {pk} FROM {Product} WHERE {modifiedtime} >= ?startDate AND {modifiedtime} <=?endDate
使用使用的hybris Commerce Suite的API的FlexibleSearch
用使用的hybris商务套件的API FlexibleSearch查询发生在两个步骤,这两者都可以在一个Java的语句来完成:
设置查询
运行查询
构建FlexibleSearch查询
一个FlexibleSearch查询被构造为包含该查询,例如字符串:
final String query = "SELECT {pk} FROM {Product}" // Flexible search service injected by Spring final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query);
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}";
String query = "SELECT {p:" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + " AS p}\n"+ "WHERE {" + ProductModel.VARIANTTYPE + "} IS NOT NULL"
调用FlexibleSearch
要调用使用API使用flexibleSearchService,这始终是可以通过Spring和必须正确注射到你的服务如下:一个 FlexibleSearch声明:
<bean id="myFancyService" class="de.hybris.platform.foobar.MyFancyService" > <property name="flexibleSearchService" ref="flexibleSearchService"/> </bean>
public class MyFancyService implements FancyService { ... private FlexibleSearchService flexibleSearchService; @Required public void setFlexibleSearchService(final FlexibleSearchService flexibleSearchService) { this.flexibleSearchService = flexibleSearchService; } ... }
该flexibleSearchService.search(...)方法返回一个de.hybris.platform.servicelayer.search.SearchResult实例,它持有的单个搜索结果列表。要访问此列表,调用更多搜索类getResult()方法,如:
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}"; final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query); List<ProductModel> result = searchResult.getResult();
然后,您可以像处理任何其他Collection情况下,这Collection实例:
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}"; final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query); final ProductModel product = searchResult.getResult().iterator().next();慎重
传递参数
传递参数,创建一个Map实例持有的参数,并通过Map search(...)方法,如:
final Map<String, Object> params = new HashMap<String, Object>(); String query = "SELECT {" + PriceRowModel.PK + "} FROM {" + PriceRowModel._TYPECODE "} "+ "WHERE {" + PriceRowModel.PRODUCT + "} = ?product AND "+ "{" + PriceRowModel.NET + "} = ?net AND "+ "{" + PriceRowModel.CURRENCY + "} = ?currency AND "+ "{" + PriceRowModel.UNIT + "} = ?unit AND "+ "{" + PriceRowModel.UNIT_FACTOR + "} = ?unitfactor AND "+ "{" + PriceRowModel.UG + "} = ?userpricegroup AND "+ "{" + PriceRowModel.MIN_QUANTITY + "} = ?minquantity AND "+ "{" + PriceRowModel.PRICE + "} = ?price "; params.put("product", product); params.put("net", priceCopy.isNet()); params.put("currency", priceCopy.getCurrency()); params.put("unit", priceCopy.getUnit()); params.put("unitfactor", priceCopy.getUnitFactor()); params.put("userpricegroup", priceCopy.getUserPriceGroup()); params.put("minquantity", priceCopy.getMinQuantity()); params.put("price", priceCopy.getPriceValue()); final SearchResult<PriceRowModel> searchResult = flexibleSearchService.search(query, params);
搜索结果的实例化
如果你只检索PKS数据库列(也就是采用hybris CommerceS SuiteSSS项目只有PKsS),并提供了一种类型的作为一个Java类,你可以立即施放的PKs表示为实际的模型实例模型。换言之,执行以下代码返回CatalogModel实例,PKs的不是Collection的Collection:
final String query = "SELECT {" + CatalogModel.PK + "} FROM {" + CatalogModel._TYPECODE + "} ORDER BY {" + CatalogModel.PK + "} ASC"; final SearchResult<CatalogModel> searchResult = flexibleSearchService.search(query);如果检索多个数据库列,您会收到结果每排几个单独的条目,你将不能够施展的搜索结果到项实例直接,没有就算检索的数据库列之一就是PK列。
使用的hybris管理控制台FlexibleSearch
触发的hybris管理控制台内FlexibleSearch查询可以有两种方法:使用SavedQuery实例和使用ViewType实例。一个ViewType实例是一个数据库视图的采用hybris Commerce Suite的代表性。一个SavedQuery实例使用FlexibleSearch查询检索采用hybris Commerce Suite的项目,而不是使用GenericSearch的一种手段。在HMC的ViewType表示称为报表定义。该SavedQuery实例是HMC仅表示,它必须指定一个与resultType和仅适用于与resultType并与resultType亚型搜索。它适用于所有类型的电子商务的hybris套房。
Go to Managing SavedQuery Items in the hybris Management Console document, section Creating a SavedQuery, for details on how to create aSavedQuery using the hybris Management Console (hMC).
Go to Managing SavedQuery Items in the hybris Management Console document, section Using a SavedQuery, for details on how to call aSavedQuery using the hMC.
Go to the Creating Report Definitions Using the hybris Management Console document for details on how to create a Report Definition using the hMC.
Some FlexibleSearch queries run the risk of returning a very large number of search results, such asSELECT * FROM {Products} WHERE {code} LIKE ?search OR {name} LIKE ?search , where?search is a parameter from a text field. Managing more than some 50 or 100 search results in one single Collection is complicated and performs comparably slow. For this reason, the FlexibleSearch framework offers a paging mechanism.
To use this paging mechanism, use thesearch(...) method withFlexibleSearchQuery object as parameter. You have to set onFlexibleSearchQuery thesetNeedTotal totrue . If this parameter is set totrue , the FlexibleSearch framework splits the number of returned search results into pages. Using thestart andrange parameters, you can retrieve pages of search results. The following code snippet, for example, iterates over all the search results of the FlexibleSearch query, three at a time:
int start = 0; final int range = 3; int total; String query = "SELECT {" + UnitModel.PK + "} FROM {"+ UnitModel._TYPECODE + "} ORDER BY " + UnitModel._TYPECODE; final FlexibleSearchQuery fQuery = new FlexibleSearchQuery(query); fQuery.setCount(range); fQuery.setNeedTotal(true); do { fQuery.setStart(start); final SearchResult<LanguageModel> searchResult = flexibleSearchService.search(fQuery); total = searchResult.getTotalCount(); start += range; } while(start < total);
Be aware that every navigation, either backward or forward, through a paged search result triggers a new search query on the database. Internally, the FlexibleSearch runs the query in full and uses an offset parameter to specify the portion of all search results to return. The fact that every navigation causes a database query has three major consequences:
Complex queries cause heavy load on the database:
Executing a simpleSELECT statement is rather fast, even with millions of search results. However, if your FlexibleSearch query requiresJOIN orUNION to execute, load on the database (and, by consequence, response times) increases rapidly. As a rule of thumb, remember that the more different items are involved, the longer the execution time is. For example, the following table gives some short examples of some rather basic FlexibleSearch statements and the actual SQL queries triggered:
https://wiki.hybris.com/display/release5/FlexibleSearch#FlexibleSearch-Basics