bloggers bloggers

Marco Napolitano
Messaggi: 79
Stelle: 0
Data: 17/02/22
Jader Jed Francia
Messaggi: 63
Stelle: 0
Data: 18/02/21
Paolo Gambetti
Messaggi: 2
Stelle: 0
Data: 11/11/19
Katia Pazzi
Messaggi: 1
Stelle: 0
Data: 27/06/19
Ezio Lombardi
Messaggi: 11
Stelle: 0
Data: 10/04/18
Chiara Mambretti
Messaggi: 25
Stelle: 0
Data: 27/02/17
Serena Traversi
Messaggi: 3
Stelle: 0
Data: 21/07/16
Francesco Falanga
Messaggi: 8
Stelle: 0
Data: 14/06/16
Antonio Musarra
Messaggi: 2
Stelle: 0
Data: 18/11/13
Simone Celli Marchi
Messaggi: 6
Stelle: 0
Data: 09/07/13
Indietro

Inidicizzazione e ricerca in Liferay

Nei post precedenti abbiamo appreso come service builder e asset framework siano gli strumenti principali candidati alla gestione dello storage di dati e metadati all'interno di Liferay. Gli stessi strumenti possono essere opportunamente utilizzati anche per la ricerca, ma le possibilità offerte sono strettamente dipendenti dai metodi esposti dal service builder o dall'asset framework.
Se volessimo effettuare una ricerca full text?
Liferay utilizza nativamente Lucene (http://lucene.apache.org) per effettuare le ricerche all'interno del portale e lo scopo di questo articolo è illustrare come rendere ricercabili le nostre entità.
Occorre innanzitutto normalizzare il nostro formato dati verso un modello basato su Document e Field e saremo noi stessi a definire quali dati appartenenti al nostro modello entreranno a far parte degli indici di Lucene per mezzo delle classi indexer.

Importante: il codice di seguito fa riferimento alla versione 6.0.6 di Liferay. A partire dalla 6.1 alcuni metodi sono stati rifattorizzati, ma le linee guida di seguito descritte sono comunque applicabili.

In liferay-portlet.xml:

<indexer-class>
it.dvel.test.indexer.MyEntityIndexer
</indexer-class>


La classe deve estendere com.liferay.portal.kernel.search.BaseIndexer e implementare i seguenti metodi:

- getClassNames
Restituisce un array di stringo contenenti i nomi delle classi relative ai model che vogliamo indicizzare.
Esempio:

public String[] getClassNames() {
return new String[]{MyEntity.class.getName()};
}


- getPortletId
Restituisce il portletID.

ATTENZIONE: per portletID si intende <portlet-name in portlet.xml>_WAR_<webapp name>. Un errore nell'implementazione di questo metodo causerà NullPointerException nascoste nelle JSP del portale in quanto il valore restituito viene utilizzato per recuperare la classe indexer: se compilato in maniera errata, nessun tipo di validazione vi segnalerà l'errore e sarete costretti a una sessione estenuante di debug.


- getSummary
Restituisce un oggetto di tipo Summary che deve contenere un titolo, una sintesi del contenuto e un url per la visualizzazione dell'elemento.
Esempio:

public Summary getSummary(Document document, String snippet,
PortletURL portletURL) {
String title = document.get(Field.TITLE);
String content = StringUtil.shorten(snippet, 200);
String resourcePrimKey = document.get(Field.ENTRY_CLASS_PK);
portletURL.setParameter("resourcePrimKey", resourcePrimKey);
return new Summary(title, content, portletURL);
}


- doGetDocument
Converte l'oggetto passato come parametro in un oggetto di tipo Document.
Esempio:

protected Document doGetDocument(Object obj) throws Exception {
MyEntity entry = (MyEntity) obj;

long companyId = entry.getCompanyId();
long groupId = getParentGroupId(entry.getGroupId());
long scopeGroupId = entry.getGroupId();
long userId = entry.getUserId();
long resourcePrimKey = entry.getPrimaryKey();
String title = entry.getTitle();
String content = entry.getText();
String description = entry.getText();
Date modifiedDate = entry.getModifiedDate();

Document document = new DocumentImpl();
document.addUID(PORTLET_ID, resourcePrimKey);
document.addModifiedDate(modifiedDate);
document.addKeyword(Field.COMPANY_ID, companyId);
document.addKeyword(Field.PORTLET_ID, getPortletId());
document.addKeyword(Field.GROUP_ID, groupId);
document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);
document.addKeyword(Field.USER_ID, userId);
document.addText(Field.TITLE, title);
document.addText(Field.CONTENT, content);
document.addText(Field.DESCRIPTION, description);
document.addKeyword(Field.ENTRY_CLASS_NAME, MyEntity.class.getName());
document.addKeyword(Field.ENTRY_CLASS_PK, resourcePrimKey);
return document;

}

ATTENZIONE: fate molta attenzione alle seguenti righe di codice:

document.addKeyword(Field.PORTLET_ID, getPortletId());

e

document.addModifiedDate(modifiedDate);

L'assenza della prima pregiudica il risultato della ricerca, escludendo le vostre entità dal risultato: non verrà lanciato nessun tipo di eccezione e nessun messaggio d'errore verrà loggato; l'assenza della seconda riga, invece, genererà un'inspiegabile "NumberFormatException for input string ''": la string vuota che viene segnalata è esattamente la data di modifica.
Altri due giorni di lavoro risparmiati.

- doReindex
I 3 metodi doReindex vengono utilizzato dal portale in fase di richiesta di reindicizzazione del repository.
Data l'istanza della nostra entità passata come parametro, è possibile effettuare l'aggiornamento utilizzando il metodo

SearchEngineUtil.updateDocument(entry.getCompanyId(), document);


L'array di stringhe presente come parametro in uno dei tre metodi rappresenta le companyIds sulle quali iterare per effettuare in reindex completo. Sarà quindi necessario implementare un ciclo sulle company passate, per ognuna delle quali sarà necessario iterare sui groups associati, per ognuno dei quali sarà necessario iterare sulle entity appartenenti al gruppo in questione. L'operazione di update verrà effettuata esattamente come indicato sopra, per mezzo del metodo SearchEngineUtil.updateDocument.

- doDelete
Questo metodo serve a rimuovere l'indice dal repository e verrà invocato dal portale contestualmente alle operazioni di cancellazione delle nostre entity.
L'implementazione è molto banale:

protected void doDelete(Object obj) throws Exception {
MyEntity entry = (MyEntity)obj;
Document document = new DocumentImpl();
document.addUID(getPortletId(), entry.getGroupId(), Long.toString(entry.getPrimaryKey()));
SearchEngineUtil.deleteDocument(entry.getCompanyId(), document.get(Field.UID));
}


Fine dell'implementazione della classe indexer.

Vediamo ora di le funzionalità di ricerca per mezzo di OpenSearch.
Come per le classi indexer, andiamo a censire in liferay-portlet.xml la classe open search relativa al nostro portlet:

<open-search-class>
it.dvel.test.search.MyEntityOpenSearch
</open-search-class>



La classe deve estendere com.liferay.portal.kernel.search.HitsOpenSearchImpl e implementare i seguenti metodi:

- getPortletId
Restituisce il portletID. LO STESSO portletID RESTITUITO NELL'INDEXER.

- getTitle
Restituisce un titolo per la ricerca effettuata

- getSearchPath
Restituisce un path descrittivo del contesto di ricerca
Esempio:

public String getSearchPath() {
return "/c/myentity/open_search";
}


Fine dell'implementazione della classe open search.

Deploy del vostro codice, aggiungete il portlet di ricerca in pagina e...fatto!

Precedente
Commenti
Nessun commento. Vuoi essere il primo.