📄 productsearch.java
字号:
/*
* $Id: ProductSearch.java,v 1.28 2004/02/26 09:10:50 jonesde Exp $
*
* Copyright (c) 2001 The Open For Business Project (www.ofbiz.org)
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.ofbiz.product.product;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilDateTime;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.GenericDelegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.condition.EntityConditionList;
import org.ofbiz.entity.condition.EntityExpr;
import org.ofbiz.entity.condition.EntityOperator;
import org.ofbiz.entity.model.DynamicViewEntity;
import org.ofbiz.entity.model.ModelKeyMap;
import org.ofbiz.entity.model.ModelViewEntity.ComplexAlias;
import org.ofbiz.entity.model.ModelViewEntity.ComplexAliasField;
import org.ofbiz.entity.transaction.GenericTransactionException;
import org.ofbiz.entity.transaction.TransactionUtil;
import org.ofbiz.entity.util.EntityFindOptions;
import org.ofbiz.entity.util.EntityListIterator;
import org.ofbiz.entity.util.EntityUtil;
/**
* Utilities for product search based on various constraints including categories, features and keywords.
*
* @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
* @version $Revision: 1.28 $
* @since 3.0
*/
public class ProductSearch {
public static final String module = ProductSearch.class.getName();
public static final String resource = "ProductUiLabels";
public static ArrayList parametricKeywordSearch(Map featureIdByType, String keywordsString, GenericDelegator delegator, String productCategoryId, String visitId, boolean anyPrefix, boolean anySuffix, boolean isAnd) {
Set featureIdSet = new HashSet();
if (featureIdByType != null) {
featureIdSet.addAll(featureIdByType.values());
}
return parametricKeywordSearch(featureIdSet, keywordsString, delegator, productCategoryId, true, visitId, anyPrefix, anySuffix, isAnd);
}
public static ArrayList parametricKeywordSearch(Set featureIdSet, String keywordsString, GenericDelegator delegator, String productCategoryId, boolean includeSubCategories, String visitId, boolean anyPrefix, boolean anySuffix, boolean isAnd) {
List productSearchConstraintList = new LinkedList();
if (UtilValidate.isNotEmpty(productCategoryId)) {
productSearchConstraintList.add(new CategoryConstraint(productCategoryId, includeSubCategories));
}
if (UtilValidate.isNotEmpty(keywordsString)) {
productSearchConstraintList.add(new KeywordConstraint(keywordsString, anyPrefix, anySuffix, null, isAnd));
}
if (featureIdSet != null && featureIdSet.size() > 0) {
Iterator featureIdIter = featureIdSet.iterator();
while (featureIdIter.hasNext()) {
String productFeatureId = (String) featureIdIter.next();
productSearchConstraintList.add(new FeatureConstraint(productFeatureId));
}
}
return searchProducts(productSearchConstraintList, new SortKeywordRelevancy(), delegator, visitId);
}
public static ArrayList searchProducts(List productSearchConstraintList, ResultSortOrder resultSortOrder, GenericDelegator delegator, String visitId) {
ProductSearchContext productSearchContext = new ProductSearchContext(delegator, visitId);
productSearchContext.addProductSearchConstraints(productSearchConstraintList);
productSearchContext.setResultSortOrder(resultSortOrder);
ArrayList productIds = productSearchContext.doSearch();
return productIds;
}
public static void getAllSubCategoryIds(String productCategoryId, Set productCategoryIdSet, GenericDelegator delegator, Timestamp nowTimestamp) {
if (nowTimestamp == null) {
nowTimestamp = UtilDateTime.nowTimestamp();
}
// this will use the GenericDelegator cache as much as possible, but not a dedicated cache because it would get stale to easily and is too much of a pain to maintain in development and production
// first make sure the current category id is in the Set
productCategoryIdSet.add(productCategoryId);
// now find all sub-categories, filtered by effective dates, and call this routine for them
try {
List productCategoryRollupList = delegator.findByAndCache("ProductCategoryRollup", UtilMisc.toMap("parentProductCategoryId", productCategoryId));
Iterator productCategoryRollupIter = productCategoryRollupList.iterator();
while (productCategoryRollupIter.hasNext()) {
GenericValue productCategoryRollup = (GenericValue) productCategoryRollupIter.next();
String subProductCategoryId = productCategoryRollup.getString("productCategoryId");
if (productCategoryIdSet.contains(subProductCategoryId)) {
// if this category has already been traversed, no use doing it again; this will also avoid infinite loops
continue;
}
// do the date filtering in the loop to avoid looping through the list twice
if (EntityUtil.isValueActive(productCategoryRollup, nowTimestamp)) {
getAllSubCategoryIds(subProductCategoryId, productCategoryIdSet, delegator, nowTimestamp);
}
}
} catch (GenericEntityException e) {
Debug.logError(e, "Error finding sub-categories for product search", module);
}
}
public static class ProductSearchContext {
public int index = 1;
public List entityConditionList = new LinkedList();
public List orderByList = new LinkedList();
public List fieldsToSelect = UtilMisc.toList("productId");
public DynamicViewEntity dynamicViewEntity = new DynamicViewEntity();
public boolean productIdGroupBy = false;
public boolean includedKeywordSearch = false;
public Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
public List keywordFixedOrSetAndList = new LinkedList();
public Set orKeywordFixedSet = new HashSet();
public Set andKeywordFixedSet = new HashSet();
public List productSearchConstraintList = new LinkedList();
public ResultSortOrder resultSortOrder = null;
public Integer resultOffset = null;
public Integer maxResults = null;
protected GenericDelegator delegator = null;
protected String visitId = null;
protected Integer totalResults = null;
public ProductSearchContext(GenericDelegator delegator, String visitId) {
this.delegator = delegator;
this.visitId = visitId;
dynamicViewEntity.addMemberEntity("PROD", "Product");
}
public GenericDelegator getDelegator() {
return this.delegator;
}
public void addProductSearchConstraints(List productSearchConstraintList) {
// Go through the constraints and add them in
Iterator productSearchConstraintIter = productSearchConstraintList.iterator();
while (productSearchConstraintIter.hasNext()) {
ProductSearchConstraint constraint = (ProductSearchConstraint) productSearchConstraintIter.next();
constraint.addConstraint(this);
}
}
public void setResultSortOrder(ResultSortOrder resultSortOrder) {
this.resultSortOrder = resultSortOrder;
}
public void setResultOffset(Integer resultOffset) {
this.resultOffset = resultOffset;
}
public void setMaxResults(Integer maxResults) {
this.maxResults = maxResults;
}
public Integer getTotalResults() {
return this.totalResults;
}
public ArrayList doSearch() {
long startMillis = System.currentTimeMillis();
// do the query
EntityListIterator eli = this.doQuery(delegator);
ArrayList productIds = this.makeProductIdList(eli);
long endMillis = System.currentTimeMillis();
double totalMillis = ((double)endMillis - (double)startMillis)/1000.0;
// store info about results in the database, attached to the user's visitId, if specified
this.saveSearchResultInfo(new Long(productIds.size()), new Double(totalMillis));
return productIds;
}
public void finishKeywordConstraints() {
if (orKeywordFixedSet.size() == 0 && andKeywordFixedSet.size() == 0 && keywordFixedOrSetAndList.size() == 0) {
return;
}
// we know we have a keyword search to do, so keep track of that now...
this.includedKeywordSearch = true;
// if there is anything in the orKeywordFixedSet add it to the keywordFixedOrSetAndList
if (orKeywordFixedSet.size() > 0) {
// put in keywordFixedOrSetAndList to process with other or lists where at least one is required
keywordFixedOrSetAndList.add(orKeywordFixedSet);
}
// remove all or sets from the or set and list where the or set is size 1 and put them in the and list
Iterator keywordFixedOrSetAndTestIter = keywordFixedOrSetAndList.iterator();
while (keywordFixedOrSetAndTestIter.hasNext()) {
Set keywordFixedOrSet = (Set) keywordFixedOrSetAndTestIter.next();
if (keywordFixedOrSet.size() == 0) {
keywordFixedOrSetAndTestIter.remove();
} else if (keywordFixedOrSet.size() == 1) {
// treat it as just another and
andKeywordFixedSet.add(keywordFixedOrSet.iterator().next());
keywordFixedOrSetAndTestIter.remove();
}
}
boolean doingBothAndOr = (keywordFixedOrSetAndList.size() > 1) || (keywordFixedOrSetAndList.size() > 0 && andKeywordFixedSet.size() > 0);
Debug.logInfo("Finished initial setup of keywords, doingBothAndOr=" + doingBothAndOr + ", andKeywordFixedSet=" + andKeywordFixedSet + "\n keywordFixedOrSetAndList=" + keywordFixedOrSetAndList, module);
ComplexAlias relevancyComplexAlias = new ComplexAlias("+");
if (andKeywordFixedSet.size() > 0) {
// add up the relevancyWeight fields from all keyword member entities for a total to sort by
Iterator keywordIter = andKeywordFixedSet.iterator();
while (keywordIter.hasNext()) {
String keyword = (String) keywordIter.next();
// make index based values and increment
String entityAlias = "PK" + index;
String prefix = "pk" + index;
index++;
dynamicViewEntity.addMemberEntity(entityAlias, "ProductKeyword");
dynamicViewEntity.addAlias(entityAlias, prefix + "Keyword", "keyword", null, null, null, null);
dynamicViewEntity.addViewLink("PROD", entityAlias, Boolean.FALSE, ModelKeyMap.makeKeyMapList("productId"));
entityConditionList.add(new EntityExpr(prefix + "Keyword", EntityOperator.LIKE, keyword));
//don't add an alias for this, will be part of a complex alias: dynamicViewEntity.addAlias(entityAlias, prefix + "RelevancyWeight", "relevancyWeight", null, null, null, null);
relevancyComplexAlias.addComplexAliasMember(new ComplexAliasField(entityAlias, "relevancyWeight"));
}
//TODO: find out why Oracle and other dbs don't like the query resulting from this and fix: productIdGroupBy = true;
if (!doingBothAndOr) {
dynamicViewEntity.addAlias(null, "totalRelevancy", null, null, null, null, null, relevancyComplexAlias);
}
}
if (keywordFixedOrSetAndList.size() > 0) {
Iterator keywordFixedOrSetAndIter = keywordFixedOrSetAndList.iterator();
while (keywordFixedOrSetAndIter.hasNext()) {
Set keywordFixedOrSet = (Set) keywordFixedOrSetAndIter.next();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -