【问题标题】:Liferay 7.3.5GA6 custom index search and ddmFieldArrayLiferay 7.3.5GA6 自定义索引搜索和ddmFieldArray
【发布时间】:2021-02-11 03:30:17
【问题描述】:

我正在尝试使用 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",
"ddmValueFieldName": "ddmFieldValueText_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]

现在,我知道这种不同的索引方式是由于改进以避免弹性问题(已超出总字段的限制)但是...执行搜索后,没有 ddmFieldArraycom.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
}

这仍然是一种改进还是只是一种意外行为?

有什么方法可以解决或扩展这个问题?

谢谢

【问题讨论】:

    标签: java elasticsearch liferay portlet liferay-7


    【解决方案1】:

    “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 的示例:

    我还实现了一个 groovy 脚本示例,您可以从以下位置执行它:控制面板 => 服务器管理 => 脚本

    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.getValues("ddmFieldArray"));
        out.println("");
    }
    

    在您的代码中,您应该将 RegistryUtil 用法替换为“@Reference”注释。

    如果您对我的示例有任何问题,请告诉我。

    【讨论】:

    • 非常感谢@jorgediaz-lr,您的解决方案运行良好,您的回答也很棒。我只是在 RegistryUtili 和 @Reference 上遇到了问题:使用此代码部署的服务有一些不满意的引用(对注册表或 registryutil)的问题,所以,现在,我将不做任何参考。再次感谢您!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 1970-01-01
    相关资源
    最近更新 更多