问题描述
我正在尝试使用SearchContext,IndexSearcherHelperUtil和其他所有东西为Liferay 7.3.5 GA6开发自定义Web内容搜索portlet。
我有一些具有不同字段的DDMStructure,并且根据我在elasticsearch索引上看到的内容,这些字段在嵌套文档中建立了索引,如下所示:
"ddmFieldArray": [
{
"ddmFieldName": "ddm__text__37702__nome_it_IT","ddmValueFieldName": "ddmFieldValueText_it_IT","ddmFieldValueText_it_IT": "Nome esempio","ddmFieldValueText_it_IT_String_sortable": "nome esempio"
},{
"ddmFieldName": "ddm__text__37702__descrizione_breve_it_IT","ddmFieldValueText_it_IT": "Esempio di descrizione breve da indicizzare","ddmFieldValueText_it_IT_String_sortable": "esempio di descrizione breve da indicizzare"
}
]
与我以前知道的旧方法不同,自定义字段的索引位置类似于ddm__[keyword/text]__[structure_id]__[field_name]
现在,我知道这种不同的索引编制方法是为了避免弹性问题(已超过总字段数限制)而进行的改进,但是...执行搜索后,没有 ddmFieldArray 在 com.liferay.portal.kernel.search.Document .getFields 中,所以我无法从弹性搜索索引中获取ddmstructure字段值。
这是代码:
long journalArticleClassId = ClassNameLocalServiceUtil.getClassNameId(JournalArticle.class.getName());
SearchContext searchContext = new SearchContext();
searchContext.setClasstypeIds(new long[] {journalArticleClassId});
searchContext.setCompanyId(companyId);
searchContext.setStart(QueryUtil.ALL_POS);
searchContext.setEnd(QueryUtil.ALL_POS);
BooleanQuery query = new BooleanQueryImpl();
MatchQuery approvedQuery = new MatchQuery(Field.STATUS,String.valueOf(WorkflowConstants.STATUS_APPROVED));
query.add(approvedQuery,BooleanClauSEOccur.MUST.getName());
Hits resultHits = IndexSearcherHelperUtil.search(searchContext,query);
for (Document doc: resultHits.getDocs()) {
doc.getFields().forEach((k,v) -> _log.debug(k)); //No ddm structure field
}
这仍然是一种改进还是只是一种意外的行为?
谢谢
解决方法
“ ddmFieldArray”字段是一个嵌套字段,默认情况下不返回该字段。 您必须从存储在Elasticsearch的内部“ _source”字段中的文档源字段中获取它(请参见https://www.elastic.co/guide/en/elasticsearch/reference/7.9/search-fields.html)
为了在Liferay中执行此操作,您必须使用一些旧的 portal-kernel 搜索类中没有的搜索方法,您必须使用可用的新搜索类在 modules / apps / portal-search
中的 portal-search-api 模块中这些是您必须对代码进行的更改:
- 执行搜索之前,您必须在搜索中添加“ fetchSource”标志,并添加以下代码:
searchRequestBuilderFactory.builder(
searchContext
).fetchSource(
true
).build();
- 执行搜索后,必须从SearchResponse对象获取Document对象。使用以下代码可在searchContext中使用此SearchResponse:
/* Execute search */
IndexSearcherHelperUtil.search(searchContext,query);
/* Get results from search response */
SearchResponse searchResponse = searchContext.getAttribute("search.response");
List<SearchHit> resultHits = searchResponse.getSearchHits().getSearchHits();
/* Iterate */
for (SearchHit searchHit : resultHits) {
Document doc = searchHit.getDocument();
...your stuff...
}
在以下Liferay类中,您有一些有关获取源代码和获取SearchResponse的示例:
- com.liferay.document.library.search.test.DLSearchFixture,请参见方法searchOnlyOneSearchHit,其中设置了fetchSource(true)并从searchContext获取SearchResponse对象
- com.liferay.account.internal.retriever.AccountOrganizationRetrieverImpl,其中一些搜索是使用SearchRequest和SearchResponse完成的。
- com.liferay.asset.internal.util.AssetHelperImpl,其中使用了searchRequestBuilderFactory。
我还实现了一个时髦的脚本示例,您可以从以下示例执行该脚本:控制面板=>服务器管理=>脚本
import com.liferay.registry.*;
import com.liferay.portal.kernel.search.*;
import com.liferay.portal.kernel.search.generic.*;
import com.liferay.portal.search.legacy.searcher.SearchRequestBuilderFactory;
import com.liferay.portal.search.searcher.SearchResponse;
import com.liferay.portal.search.hits.SearchHit;
import com.liferay.portal.search.document.Document;
/* Get SearchRequestBuilderFactory reference using RegistryUtil,because we cannot use "@Reference" in a groovy script */
Registry registry = RegistryUtil.getRegistry();
SearchRequestBuilderFactory searchRequestBuilderFactory = registry.getService(registry.getServiceReference(SearchRequestBuilderFactory.class.getName()));
/* Create SearchContext */
SearchContext searchContext = new SearchContext();
searchContext.setCompanyId(com.liferay.portal.kernel.util.PortalUtil.getCompany(actionRequest).getCompanyId());
searchContext.setStart(-1);
searchContext.setEnd(-1);
/* Line to fetch stored source of documents */
searchRequestBuilderFactory.builder(
searchContext
).fetchSource(
true
).build();
/* Get journal articles that are approved (status = 0) */
MatchQuery approvedQuery = new MatchQuery(Field.STATUS,String.valueOf(0));
MatchQuery journalArticleQuery = new MatchQuery("entryClassName",com.liferay.journal.model.JournalArticle.class.getName());
BooleanQuery query = new BooleanQueryImpl();
query.add(approvedQuery,BooleanClauseOccur.MUST.getName());
query.add(journalArticleQuery,BooleanClauseOccur.MUST.getName());
/* Execute search */
IndexSearcherHelperUtil.search(searchContext,query);
/* Get results from search response */
SearchResponse searchResponse = searchContext.getAttribute("search.response");
List<SearchHit> resultHits = searchResponse.getSearchHits().getSearchHits();
/* Iterate */
for (SearchHit searchHit : resultHits) {
Document doc = searchHit.getDocument();
out.println("entryClassPK: " + doc.getValue("entryClassPK"));
out.println("ddmFieldArray: " + doc.getValue("ddmFieldArray"));
out.println("");
}
在您的代码中,应将RegistryUtil用法替换为“ @Reference”注释。
让我知道您的示例是否有问题。