| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.apache.ofbiz.content.search; |
| |
| import java.io.IOException; |
| import java.sql.Timestamp; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import org.apache.lucene.document.Document; |
| import org.apache.lucene.document.DoublePoint; |
| import org.apache.lucene.document.Field; |
| import org.apache.lucene.document.LongPoint; |
| import org.apache.lucene.document.StringField; |
| import org.apache.lucene.document.TextField; |
| import org.apache.lucene.index.Term; |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.GeneralException; |
| import org.apache.ofbiz.base.util.UtilDateTime; |
| import org.apache.ofbiz.base.util.UtilMisc; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.content.data.DataResourceWorker; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.GenericEntityException; |
| import org.apache.ofbiz.entity.GenericValue; |
| import org.apache.ofbiz.entity.condition.EntityCondition; |
| import org.apache.ofbiz.entity.condition.EntityOperator; |
| import org.apache.ofbiz.entity.util.EntityQuery; |
| import org.apache.ofbiz.entity.util.EntityUtil; |
| import org.apache.ofbiz.entity.util.EntityUtilProperties; |
| |
| public class ProductDocument implements LuceneDocument { |
| private static final String module = ProductDocument.class.getName(); |
| private static final String NULL_STRING = "NULL"; |
| private final Term documentIdentifier; |
| |
| public ProductDocument(String productId) { |
| this.documentIdentifier = new Term("productId", productId); |
| } |
| |
| @Override |
| public String toString() { |
| return getDocumentIdentifier().toString(); |
| } |
| |
| public Term getDocumentIdentifier() { |
| return documentIdentifier; |
| } |
| |
| public Document prepareDocument(Delegator delegator) { |
| String productId = getDocumentIdentifier().text(); |
| try { |
| GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).queryOne(); |
| if (product == null) { |
| // Return a null document (we will remove the document from the index) |
| return null; |
| } else { |
| if ("Y".equals(product.getString("isVariant")) && "true".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.ignore.variants", delegator))) { |
| return null; |
| } |
| Document doc = new Document(); |
| Timestamp nextReIndex = null; |
| |
| // Product Fields |
| doc.add(new StringField("productId", productId, Field.Store.YES)); |
| this.addTextFieldByWeight(doc, "productName", product.getString("productName"), "index.weight.Product.productName", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "internalName", product.getString("internalName"), "index.weight.Product.internalName", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "brandName", product.getString("brandName"), "index.weight.Product.brandName", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "description", product.getString("description"), "index.weight.Product.description", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "longDescription", product.getString("longDescription"), "index.weight.Product.longDescription", 0, false, "fullText", delegator); |
| // OFBiz-8316, the LongPoint should be reused when updating to Solr 6.4.1 or later |
| doc.add(new StringField("introductionDate", String.valueOf(quantizeTimestampToDays(product.getTimestamp("introductionDate"))), Field.Store.NO)); |
| // doc.add(new LongPoint("introductionDate", quantizeTimestampToDays(product.getTimestamp("introductionDate")))); |
| nextReIndex = this.checkSetNextReIndex(product.getTimestamp("introductionDate"), nextReIndex); |
| // OFBiz-8316, the LongPoint should be reused when updating to Solr 6.4.1 or later |
| // doc.add(new LongField("salesDiscontinuationDate", quantizeTimestampToDays(product.getTimestamp("salesDiscontinuationDate")), Field.Store.NO)); |
| doc.add(new StringField("salesDiscontinuationDate", String.valueOf(quantizeTimestampToDays(product.getTimestamp("salesDiscontinuationDate"))), Field.Store.NO)); |
| // doc.add(new LongPoint("salesDiscontinuationDate", quantizeTimestampToDays(product.getTimestamp("salesDiscontinuationDate")))); |
| nextReIndex = this.checkSetNextReIndex(product.getTimestamp("salesDiscontinuationDate"), nextReIndex); |
| doc.add(new StringField("isVariant", product.get("isVariant") != null && product.getBoolean("isVariant") ? "true" : "false", Field.Store.NO)); |
| |
| // ProductFeature Fields, check that at least one of the fields is set to be indexed |
| if (!"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.ProductFeatureAndAppl.description", "0", delegator)) || |
| !"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.ProductFeatureAndAppl.abbrev", "0", delegator)) || |
| !"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.ProductFeatureAndAppl.idCode", "0", delegator))) { |
| |
| List<GenericValue> productFeatureAndAppls = EntityQuery.use(delegator).from("ProductFeatureAndAppl").where("productId", productId).queryList(); |
| productFeatureAndAppls = this.filterByThruDate(productFeatureAndAppls); |
| |
| for (GenericValue productFeatureAndAppl: productFeatureAndAppls) { |
| Timestamp fromDate = productFeatureAndAppl.getTimestamp("fromDate"); |
| Timestamp thruDate = productFeatureAndAppl.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| doc.add(new StringField("productFeatureId", productFeatureAndAppl.getString("productFeatureId"), Field.Store.NO)); |
| doc.add(new StringField("productFeatureCategoryId", productFeatureAndAppl.getString("productFeatureCategoryId"), Field.Store.NO)); |
| doc.add(new StringField("productFeatureTypeId", productFeatureAndAppl.getString("productFeatureTypeId"), Field.Store.NO)); |
| this.addTextFieldByWeight(doc, "featureDescription", productFeatureAndAppl.getString("description"), "index.weight.ProductFeatureAndAppl.description", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "featureAbbreviation", productFeatureAndAppl.getString("abbrev"), "index.weight.ProductFeatureAndAppl.abbrev", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "featureCode", productFeatureAndAppl.getString("idCode"), "index.weight.ProductFeatureAndAppl.idCode", 0, false, "fullText", delegator); |
| // Get the ProductFeatureGroupIds |
| List<GenericValue> productFeatureGroupAppls = EntityQuery.use(delegator).from("ProductFeatureGroupAppl").where("productFeatureId", productFeatureAndAppl.get("productFeatureId")).queryList(); |
| productFeatureGroupAppls = this.filterByThruDate(productFeatureGroupAppls); |
| for (GenericValue productFeatureGroupAppl : productFeatureGroupAppls) { |
| fromDate = productFeatureGroupAppl.getTimestamp("fromDate"); |
| thruDate = productFeatureGroupAppl.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| doc.add(new StringField("productFeatureGroupId", productFeatureGroupAppl.getString("productFeatureGroupId"), Field.Store.NO)); |
| } |
| } |
| } |
| |
| // ProductAttribute Fields |
| if (!"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.ProductAttribute.attrName", "0", delegator)) || |
| !"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.ProductAttribute.attrValue", "0", delegator))) { |
| |
| List<GenericValue> productAttributes = EntityQuery.use(delegator).from("ProductAttribute").where("productId", productId).queryList(); |
| for (GenericValue productAttribute: productAttributes) { |
| this.addTextFieldByWeight(doc, "attributeName", productAttribute.getString("attrName"), "index.weight.ProductAttribute.attrName", 0, false, "fullText", delegator); |
| this.addTextFieldByWeight(doc, "attributeValue", productAttribute.getString("attrValue"), "index.weight.ProductAttribute.attrValue", 0, false, "fullText", delegator); |
| } |
| } |
| |
| // GoodIdentification |
| if (!"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.GoodIdentification.idValue", "0", delegator))) { |
| List<GenericValue> goodIdentifications = EntityQuery.use(delegator).from("GoodIdentification").where("productId", productId).queryList(); |
| for (GenericValue goodIdentification: goodIdentifications) { |
| String goodIdentificationTypeId = goodIdentification.getString("goodIdentificationTypeId"); |
| String idValue = goodIdentification.getString("idValue"); |
| doc.add(new StringField("goodIdentificationTypeId", goodIdentificationTypeId, Field.Store.NO)); |
| doc.add(new StringField(goodIdentificationTypeId + "_GoodIdentification", idValue, Field.Store.NO)); |
| this.addTextFieldByWeight(doc, "identificationValue", idValue, "index.weight.GoodIdentification.idValue", 0, false, "fullText", delegator); |
| } |
| } |
| |
| // Virtual ProductIds |
| if ("Y".equals(product.getString("isVirtual"))) { |
| if (!"0".equals(EntityUtilProperties.getPropertyValue("prodsearch", "index.weight.Variant.Product.productId", "0", delegator))) { |
| List<GenericValue> variantProductAssocs = EntityQuery.use(delegator).from("ProductAssoc").where("productId", productId, "productAssocTypeId", "PRODUCT_VARIANT").queryList(); |
| variantProductAssocs = this.filterByThruDate(variantProductAssocs); |
| for (GenericValue variantProductAssoc: variantProductAssocs) { |
| Timestamp fromDate = variantProductAssoc.getTimestamp("fromDate"); |
| Timestamp thruDate = variantProductAssoc.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| this.addTextFieldByWeight(doc, "variantProductId", variantProductAssoc.getString("productIdTo"), "index.weight.Variant.Product.productId", 0, false, "fullText", delegator); |
| } |
| } |
| } |
| |
| // Index product content |
| String productContentTypes = EntityUtilProperties.getPropertyValue("prodsearch", "index.include.ProductContentTypes", delegator); |
| for (String productContentTypeId: productContentTypes.split(",")) { |
| int weight = 1; |
| try { |
| // this is defaulting to a weight of 1 because you specified you wanted to index this type |
| weight = EntityUtilProperties.getPropertyAsInteger("prodsearch", "index.weight.ProductContent." + productContentTypeId, 1).intValue(); |
| } catch (Exception e) { |
| Debug.logWarning("Could not parse weight number: " + e.toString(), module); |
| } |
| |
| List<GenericValue> productContentAndInfos = EntityQuery.use(delegator).from("ProductContentAndInfo").where("productId", productId, "productContentTypeId", productContentTypeId).queryList(); |
| productContentAndInfos = this.filterByThruDate(productContentAndInfos); |
| for (GenericValue productContentAndInfo: productContentAndInfos) { |
| Timestamp fromDate = productContentAndInfo.getTimestamp("fromDate"); |
| Timestamp thruDate = productContentAndInfo.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| try { |
| Map<String, Object> drContext = UtilMisc.<String, Object>toMap("product", product); |
| String contentText = DataResourceWorker.renderDataResourceAsText(null, delegator, productContentAndInfo.getString("dataResourceId"), drContext, null, null, false); |
| this.addTextFieldByWeight(doc, "content", contentText, null, weight, false, "fullText", delegator); |
| } catch (IOException e1) { |
| Debug.logError(e1, "Error getting content text to index", module); |
| } catch (GeneralException e1) { |
| Debug.logError(e1, "Error getting content text to index", module); |
| } |
| |
| // TODO: Not indexing alternate locales, needs special handling |
| /* |
| List<GenericValue> alternateViews = productContentAndInfo.getRelated("ContentAssocDataResourceViewTo", UtilMisc.toMap("caContentAssocTypeId", "ALTERNATE_LOCALE"), UtilMisc.toList("-caFromDate")); |
| alternateViews = EntityUtil.filterByDate(alternateViews, UtilDateTime.nowTimestamp(), "caFromDate", "caThruDate", true); |
| for (GenericValue thisView: alternateViews) { |
| } |
| */ |
| } |
| } |
| |
| // Index the product's directProductCategoryIds (direct parents), productCategoryIds (all ancestors) and prodCatalogIds |
| this.populateCategoryData(doc, product); |
| |
| // Index ProductPrices, uses dynamic fields in the format ${productPriceTypeId}_${productPricePurposeId}_${currencyUomId}_${productStoreGroupId}_price |
| List<GenericValue> productPrices = product.getRelated("ProductPrice", null, null, false); |
| productPrices = this.filterByThruDate(productPrices); |
| for (GenericValue productPrice : productPrices) { |
| Timestamp fromDate = productPrice.getTimestamp("fromDate"); |
| Timestamp thruDate = productPrice.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| StringBuilder fieldNameSb = new StringBuilder(); |
| fieldNameSb.append(productPrice.getString("productPriceTypeId")); |
| fieldNameSb.append('_'); |
| fieldNameSb.append(productPrice.getString("productPricePurposeId")); |
| fieldNameSb.append('_'); |
| fieldNameSb.append(productPrice.getString("currencyUomId")); |
| fieldNameSb.append('_'); |
| fieldNameSb.append(productPrice.getString("productStoreGroupId")); |
| fieldNameSb.append("_price"); |
| // OFBiz-8316, the DoublePoint should be reused when updating to Solr 6.4.1 or later |
| // doc.add(new DoubleField(fieldNameSb.toString(), productPrice.getDouble("price"), Field.Store.NO)); |
| doc.add(new StringField(fieldNameSb.toString(), String.valueOf(productPrice.getDouble("price")), Field.Store.NO)); |
| // doc.add(new DoublePoint(fieldNameSb.toString(), productPrice.getDouble("price"))); |
| } |
| |
| // Index ProductSuppliers |
| List<GenericValue> supplierProducts = product.getRelated("SupplierProduct", null, null, false); |
| supplierProducts = this.filterByThruDate(supplierProducts, "availableThruDate"); |
| Set<String> supplierPartyIds = new TreeSet<String>(); |
| for (GenericValue supplierProduct : supplierProducts) { |
| Timestamp fromDate = supplierProduct.getTimestamp("availableFromDate"); |
| Timestamp thruDate = supplierProduct.getTimestamp("availableThruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| supplierPartyIds.add(supplierProduct.getString("partyId")); |
| } |
| for (String supplierPartyId : supplierPartyIds) { |
| doc.add(new StringField("supplierPartyId", supplierPartyId, Field.Store.NO)); |
| } |
| |
| // TODO: Add the nextReIndex timestamp to the document for when the product should be automatically re-indexed outside of any ECAs |
| // based on the next known from/thru date whose passing will cause a change to the document. Need to build a scheduled service to look for these. |
| return doc; |
| } |
| } catch (GenericEntityException e) { |
| Debug.logError(e, module); |
| } |
| return null; |
| } |
| |
| // An attempt to boost/weight values in a similar manner to what OFBiz product search does. |
| private void addTextFieldByWeight(Document doc, String fieldName, String value, String property, int defaultWeight, boolean store, String fullTextFieldName, Delegator delegator) { |
| if (fieldName == null) return; |
| |
| float weight = 0; |
| if (property != null) { |
| try { |
| weight = EntityUtilProperties.getPropertyAsFloat("prodsearch", property, 0).floatValue(); |
| } catch (Exception e) { |
| Debug.logWarning("Could not parse weight number: " + e.toString(), module); |
| } |
| } else if (defaultWeight > 0) { |
| weight = defaultWeight; |
| } |
| if (weight == 0 && !store) { |
| return; |
| } |
| Field field = new TextField(fieldName, checkValue(value), (store? Field.Store.YES: Field.Store.NO)); |
| if (weight > 0 && weight != 1) { |
| field.setBoost(weight); |
| } |
| doc.add(field); |
| if (fullTextFieldName != null) { |
| doc.add(new TextField(fullTextFieldName, checkValue(value), Field.Store.NO)); |
| } |
| } |
| |
| private String checkValue(String value) { |
| if (UtilValidate.isEmpty(value)) { |
| return NULL_STRING; |
| } |
| return value; |
| } |
| |
| private Timestamp checkSetNextReIndex(Timestamp nextValue, Timestamp currentValue) { |
| // nextValue is null, stick with what we've got |
| if (nextValue == null) return currentValue; |
| // currentValue is null so use nextValue |
| if (currentValue == null) return nextValue; |
| // currentValue is after nextValue so use nextValue |
| if (currentValue.after(nextValue)) return nextValue; |
| // stick with current value |
| return currentValue; |
| } |
| |
| private static final EntityCondition THRU_DATE_ONLY_CONDITION = EntityCondition.makeCondition( |
| EntityCondition.makeCondition("thruDate", EntityOperator.EQUALS, null), |
| EntityOperator.OR, |
| EntityCondition.makeCondition("thruDate", EntityOperator.GREATER_THAN, UtilDateTime.nowTimestamp()) |
| ); |
| |
| private List<GenericValue> filterByThruDate(List<GenericValue> values) { |
| return EntityUtil.filterByCondition(values, THRU_DATE_ONLY_CONDITION); |
| } |
| |
| private List<GenericValue> filterByThruDate(List<GenericValue> values, String thruDateName) { |
| return EntityUtil.filterByCondition(values, EntityCondition.makeCondition( |
| EntityCondition.makeCondition(thruDateName, EntityOperator.EQUALS, null), |
| EntityOperator.OR, |
| EntityCondition.makeCondition(thruDateName, EntityOperator.GREATER_THAN, UtilDateTime.nowTimestamp()) |
| )); |
| } |
| |
| private Timestamp populateCategoryData(Document doc, GenericValue product) throws GenericEntityException { |
| Timestamp nextReIndex = null; |
| Set<String> indexedCategoryIds = new TreeSet<String>(); |
| List<GenericValue> productCategoryMembers = product.getRelated("ProductCategoryMember", null, null, false); |
| productCategoryMembers = this.filterByThruDate(productCategoryMembers); |
| |
| for (GenericValue productCategoryMember: productCategoryMembers) { |
| String productCategoryId = productCategoryMember.getString("productCategoryId"); |
| doc.add(new StringField("productCategoryId", productCategoryId, Field.Store.NO)); |
| doc.add(new StringField("directProductCategoryId", productCategoryId, Field.Store.NO)); |
| indexedCategoryIds.add(productCategoryId); |
| Timestamp fromDate = productCategoryMember.getTimestamp("fromDate"); |
| Timestamp thruDate = productCategoryMember.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index the feature |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| nextReIndex = this.checkSetNextReIndex( |
| this.getParentCategories(doc, productCategoryMember.getRelatedOne("ProductCategory", false), indexedCategoryIds), |
| nextReIndex); |
| } |
| return nextReIndex; |
| } |
| |
| private Timestamp getParentCategories(Document doc, GenericValue productCategory, Set<String> indexedCategoryIds) throws GenericEntityException { |
| return this.getParentCategories(doc, productCategory, indexedCategoryIds, new TreeSet<String>()); |
| } |
| |
| private Timestamp getParentCategories(Document doc, GenericValue productCategory, Set<String> indexedCategoryIds, Set<String> indexedCatalogIds) throws GenericEntityException { |
| Timestamp nextReIndex = null; |
| nextReIndex = this.getCategoryCatalogs(doc, productCategory, indexedCatalogIds); |
| List<GenericValue> productCategoryRollups = productCategory.getRelated("CurrentProductCategoryRollup", null, null, false); |
| productCategoryRollups = this.filterByThruDate(productCategoryRollups); |
| for (GenericValue productCategoryRollup : productCategoryRollups) { |
| Timestamp fromDate = productCategoryRollup.getTimestamp("fromDate"); |
| Timestamp thruDate = productCategoryRollup.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index now |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| // Skip if we've done this category already |
| if (!indexedCategoryIds.add(productCategoryRollup.getString("parentProductCategoryId"))) { |
| continue; |
| } |
| GenericValue parentProductCategory = productCategoryRollup.getRelatedOne("ParentProductCategory", false); |
| doc.add(new StringField("productCategoryId", parentProductCategory.getString("productCategoryId"), Field.Store.NO)); |
| nextReIndex = this.checkSetNextReIndex( |
| this.getParentCategories(doc, parentProductCategory, indexedCategoryIds), |
| nextReIndex |
| ); |
| } |
| return nextReIndex; |
| } |
| |
| private Timestamp getCategoryCatalogs(Document doc, GenericValue productCategory, Set<String> indexedCatalogIds) throws GenericEntityException { |
| Timestamp nextReIndex = null; |
| List<GenericValue> prodCatalogCategories = productCategory.getRelated("ProdCatalogCategory", null, null, false); |
| prodCatalogCategories = this.filterByThruDate(prodCatalogCategories); |
| for (GenericValue prodCatalogCategory : prodCatalogCategories) { |
| Timestamp fromDate = prodCatalogCategory.getTimestamp("fromDate"); |
| Timestamp thruDate = prodCatalogCategory.getTimestamp("thruDate"); |
| if (fromDate != null && fromDate.after(UtilDateTime.nowTimestamp())) { |
| // fromDate is after now, update reindex date but don't index now |
| nextReIndex = this.checkSetNextReIndex(fromDate, nextReIndex); |
| continue; |
| } else if (thruDate != null) { |
| nextReIndex = this.checkSetNextReIndex(thruDate, nextReIndex); |
| } |
| // Skip if we've done this catalog already |
| if (!indexedCatalogIds.add(prodCatalogCategory.getString("prodCatalogId"))) { |
| continue; |
| } |
| doc.add(new StringField("prodCatalogId", prodCatalogCategory.getString("prodCatalogId"), Field.Store.NO)); |
| } |
| return nextReIndex; |
| } |
| |
| private long quantizeTimestampToDays(Timestamp date) { |
| long quantizedDate = 0; |
| if (date != null) { |
| quantizedDate = date.getTime()/24/3600; |
| } |
| return quantizedDate; |
| } |
| |
| } |