
com.liferay.search.experiences.internal.suggestions.spi.SXPBlueprintSuggestionsContributor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.search.experiences.service
Show all versions of com.liferay.search.experiences.service
Liferay Search Experiences Service
The newest version!
/**
* SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
* SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
*/
package com.liferay.search.experiences.internal.suggestions.spi;
import com.liferay.asset.kernel.AssetRendererFactoryRegistryUtil;
import com.liferay.asset.kernel.model.AssetRenderer;
import com.liferay.asset.kernel.model.AssetRendererFactory;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.feature.flag.FeatureFlagManagerUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.ClassName;
import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.service.ClassNameLocalService;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.MapUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.search.asset.AssetURLViewProvider;
import com.liferay.portal.search.constants.SearchContextAttributes;
import com.liferay.portal.search.document.Document;
import com.liferay.portal.search.hits.SearchHit;
import com.liferay.portal.search.hits.SearchHits;
import com.liferay.portal.search.rest.dto.v1_0.SuggestionsContributorConfiguration;
import com.liferay.portal.search.searcher.SearchRequest;
import com.liferay.portal.search.searcher.SearchRequestBuilder;
import com.liferay.portal.search.searcher.SearchRequestBuilderFactory;
import com.liferay.portal.search.searcher.SearchResponse;
import com.liferay.portal.search.searcher.Searcher;
import com.liferay.portal.search.spi.suggestions.SuggestionsContributor;
import com.liferay.portal.search.suggestions.Suggestion;
import com.liferay.portal.search.suggestions.SuggestionBuilder;
import com.liferay.portal.search.suggestions.SuggestionBuilderFactory;
import com.liferay.portal.search.suggestions.SuggestionsContributorResults;
import com.liferay.portal.search.suggestions.SuggestionsContributorResultsBuilderFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* @author Petteri Karttunen
*/
@Component(
enabled = false,
property = "search.suggestions.contributor.name=sxpBlueprint",
service = SuggestionsContributor.class
)
public class SXPBlueprintSuggestionsContributor
implements SuggestionsContributor {
@Override
public SuggestionsContributorResults getSuggestionsContributorResults(
LiferayPortletRequest liferayPortletRequest,
LiferayPortletResponse liferayPortletResponse,
SearchContext searchContext,
SuggestionsContributorConfiguration
suggestionsContributorConfiguration) {
Map attributes =
(Map)
suggestionsContributorConfiguration.getAttributes();
if ((attributes == null) ||
(!attributes.containsKey("sxpBlueprintExternalReferenceCode") &&
!attributes.containsKey("sxpBlueprintId"))) {
if (_log.isDebugEnabled()) {
_log.debug(
"Attributes do not contain search experiences blueprint " +
"External Reference Code or ID");
}
return null;
}
if (!_exceedsCharacterThreshold(
attributes, searchContext.getKeywords())) {
return null;
}
SearchResponse searchResponse = _searcher.search(
_getSearchRequest(
attributes, searchContext,
GetterUtil.getInteger(
suggestionsContributorConfiguration.getSize(), 5)));
SearchHits searchHits = searchResponse.getSearchHits();
if (searchHits.getTotalHits() == 0) {
return null;
}
return _suggestionsContributorResultsBuilderFactory.builder(
).displayGroupName(
suggestionsContributorConfiguration.getDisplayGroupName()
).suggestions(
_getSuggestions(
attributes, liferayPortletRequest, liferayPortletResponse,
searchContext, searchHits.getSearchHits())
).build();
}
private boolean _exceedsCharacterThreshold(
Map attributes, String keywords) {
int characterThreshold = _getCharacterThreshold(attributes);
if (Validator.isBlank(keywords)) {
if (characterThreshold == 0) {
return true;
}
}
else if (keywords.length() >= characterThreshold) {
return true;
}
return false;
}
private AssetRenderer> _getAssetRenderer(
AssetRendererFactory> assetRendererFactory, long entryClassPK) {
try {
return assetRendererFactory.getAssetRenderer(entryClassPK);
}
catch (PortalException portalException) {
_log.error(portalException);
return null;
}
}
private int _getCharacterThreshold(Map attributes) {
if (attributes == null) {
return _CHARACTER_THRESHOLD;
}
return MapUtil.getInteger(
attributes, "characterThreshold", _CHARACTER_THRESHOLD);
}
private Map _getFieldValues(
Document document, List fieldNames, Locale locale) {
Map fieldValues = new HashMap<>();
for (String fieldName : fieldNames) {
fieldName = _replaceLanguageId(locale, fieldName);
fieldValues.put(fieldName, document.getValue(fieldName));
}
return fieldValues;
}
private String[] _getNestedFieldValue(Document document, String fieldName) {
String[] parts = StringUtil.split(fieldName, "\\.");
Map nestedFields = (Map)document.getValue(
parts[0]);
if (nestedFields == null) {
return null;
}
return GetterUtil.getStringValues(nestedFields.get(parts[1]));
}
private SearchRequest _getSearchRequest(
Map attributes, SearchContext searchContext1,
int size) {
SearchRequestBuilder searchRequestBuilder =
_searchRequestBuilderFactory.builder();
searchRequestBuilder.from(
0
).queryString(
searchContext1.getKeywords()
).size(
size
).withSearchContext(
searchContext2 -> {
_setSearchExperiencesSearchContextAttributes(
attributes, searchContext1, searchContext2);
searchContext2.setAttribute(
SearchContextAttributes.
ATTRIBUTE_KEY_CONTRIBUTE_TUNING_RANKINGS,
Boolean.TRUE);
searchContext2.setAttribute(
SearchContextAttributes.ATTRIBUTE_KEY_EMPTY_SEARCH,
searchContext1.getAttribute(
SearchContextAttributes.ATTRIBUTE_KEY_EMPTY_SEARCH));
searchContext2.setCompanyId(searchContext1.getCompanyId());
searchContext2.setGroupIds(searchContext1.getGroupIds());
if (FeatureFlagManagerUtil.isEnabled("LPD-35128")) {
searchContext2.setIncludeAttachments(
MapUtil.getBoolean(attributes, "includeAttachments"));
}
searchContext2.setKeywords(searchContext1.getKeywords());
searchContext2.setLocale(searchContext1.getLocale());
searchContext2.setTimeZone(searchContext1.getTimeZone());
searchContext2.setUserId(searchContext1.getUserId());
}
);
return searchRequestBuilder.build();
}
private Suggestion _getSuggestion(
List fieldNames, boolean includeAssetSearchSummary,
boolean includeAssetURL, LiferayPortletRequest liferayPortletRequest,
LiferayPortletResponse liferayPortletResponse,
SearchContext searchContext, SearchHit searchHit, String text,
boolean useAssetTitle) {
SuggestionBuilder suggestionBuilder = _suggestionBuilderFactory.builder(
).score(
searchHit.getScore()
).text(
text
);
Document document = searchHit.getDocument();
if (ListUtil.isNotEmpty(fieldNames)) {
suggestionBuilder.attribute(
"fields",
_getFieldValues(
document, fieldNames, searchContext.getLocale()));
}
if (!includeAssetSearchSummary && !includeAssetURL && !useAssetTitle) {
return suggestionBuilder.build();
}
try {
_setAssetFields(
document, includeAssetSearchSummary, includeAssetURL,
liferayPortletRequest, liferayPortletResponse,
searchContext.getLocale(), suggestionBuilder, useAssetTitle);
}
catch (Exception exception) {
_log.error(exception);
}
return suggestionBuilder.build();
}
private List _getSuggestions(
Map attributes,
LiferayPortletRequest liferayPortletRequest,
LiferayPortletResponse liferayPortletResponse,
SearchContext searchContext, List searchHits) {
List suggestions = new ArrayList<>();
List fieldNames = (List)attributes.get("fields");
String fieldValueSeparator = MapUtil.getString(
attributes, "fieldValueSeparator");
boolean includeAssetSearchSummary = MapUtil.getBoolean(
attributes, "includeAssetSearchSummary", true);
boolean includeAssetURL = MapUtil.getBoolean(
attributes, "includeAssetURL", true);
String textFieldName = MapUtil.getString(attributes, "textField");
for (SearchHit searchHit : searchHits) {
Document document = searchHit.getDocument();
if (Validator.isBlank(textFieldName)) {
suggestions.add(
_getSuggestion(
fieldNames, includeAssetSearchSummary, includeAssetURL,
liferayPortletRequest, liferayPortletResponse,
searchContext, searchHit, StringPool.BLANK, true));
continue;
}
List texts = _getTexts(
document,
_replaceLanguageId(searchContext.getLocale(), textFieldName));
for (String text : texts) {
if (!Validator.isBlank(fieldValueSeparator)) {
String[] parts = StringUtil.split(
text, fieldValueSeparator);
for (String part : parts) {
suggestions.add(
_getSuggestion(
fieldNames, includeAssetSearchSummary,
includeAssetURL, liferayPortletRequest,
liferayPortletResponse, searchContext,
searchHit, part, false));
}
}
else {
suggestions.add(
_getSuggestion(
fieldNames, includeAssetSearchSummary,
includeAssetURL, liferayPortletRequest,
liferayPortletResponse, searchContext, searchHit,
text, false));
}
}
}
return suggestions;
}
private List _getTexts(Document document, String fieldName) {
if (StringUtil.contains(fieldName, ".")) {
return Arrays.asList(_getNestedFieldValue(document, fieldName));
}
return document.getStrings(fieldName);
}
private String _replaceLanguageId(Locale locale, String fieldName) {
return StringUtil.replace(
fieldName, "${language_id}", LocaleUtil.toLanguageId(locale));
}
private void _setAssetFields(
Document document, boolean includeAssetSearchSummary,
boolean includeAssetURL,
LiferayPortletRequest liferayPortletRequest,
LiferayPortletResponse liferayPortletResponse, Locale locale,
SuggestionBuilder suggestionBuilder, boolean useAssetTitle)
throws Exception {
String entryClassName = document.getString(Field.ENTRY_CLASS_NAME);
AssetRendererFactory> assetRendererFactory =
AssetRendererFactoryRegistryUtil.getAssetRendererFactoryByClassName(
entryClassName);
if (assetRendererFactory == null) {
return;
}
long entryClassPK = document.getLong(Field.ENTRY_CLASS_PK);
AssetRenderer> assetRenderer = _getAssetRenderer(
assetRendererFactory, entryClassPK);
if (assetRenderer == null) {
return;
}
if (includeAssetSearchSummary) {
suggestionBuilder.attribute(
"assetSearchSummary",
assetRenderer.getSummary(
liferayPortletRequest, liferayPortletResponse));
}
if (includeAssetURL) {
String assetClassName = entryClassName;
long assetClassPK = entryClassPK;
long classNameId = GetterUtil.getLong(
document.getValue(Field.CLASS_NAME_ID));
long classPK = GetterUtil.getLong(
document.getValue(Field.CLASS_PK));
if ((classNameId > 0) && (classPK > 0)) {
ClassName className = _classNameLocalService.getClassName(
classNameId);
AssetRendererFactory> classNameAssetRendererFactory =
AssetRendererFactoryRegistryUtil.
getAssetRendererFactoryByClassName(
className.getClassName());
if (classNameAssetRendererFactory != null) {
assetClassName = className.getClassName();
assetClassPK = classPK;
}
}
suggestionBuilder.attribute(
"assetURL",
_assetURLViewProvider.getAssetURLView(
assetRenderer, assetRendererFactory, assetClassName,
assetClassPK, liferayPortletRequest,
liferayPortletResponse));
}
if (useAssetTitle) {
suggestionBuilder.text(assetRenderer.getTitle(locale));
}
}
private void _setSearchExperiencesSearchContextAttributes(
Map attributes, SearchContext sourceSearchContext,
SearchContext targetSearchContext) {
MapUtil.isNotEmptyForEach(
attributes,
(key, value) -> {
if (key.startsWith("search.experiences.") && (value != null) &&
(value instanceof Serializable)) {
targetSearchContext.setAttribute(key, (Serializable)value);
}
});
MapUtil.isNotEmptyForEach(
sourceSearchContext.getAttributes(),
(key, value) -> {
if (key.startsWith("search.experiences.") && (value != null)) {
targetSearchContext.setAttribute(key, value);
}
});
targetSearchContext.setAttribute(
"search.experiences.blueprint.external.reference.code",
MapUtil.getString(attributes, "sxpBlueprintExternalReferenceCode"));
targetSearchContext.setAttribute(
"search.experiences.blueprint.id",
MapUtil.getLong(attributes, "sxpBlueprintId"));
}
private static final int _CHARACTER_THRESHOLD = 2;
private static final Log _log = LogFactoryUtil.getLog(
SXPBlueprintSuggestionsContributor.class);
@Reference
private AssetURLViewProvider _assetURLViewProvider;
@Reference
private ClassNameLocalService _classNameLocalService;
@Reference
private Searcher _searcher;
@Reference
private SearchRequestBuilderFactory _searchRequestBuilderFactory;
@Reference
private SuggestionBuilderFactory _suggestionBuilderFactory;
@Reference
private SuggestionsContributorResultsBuilderFactory
_suggestionsContributorResultsBuilderFactory;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy