Permalink
Browse files

use hibernate search in GetTransUnitListHandler

  • Loading branch information...
1 parent d6f80e0 commit 722b5d89750998ccc6de4821a03a862a73bc2e32 @huangp huangp committed Jun 27, 2012
@@ -21,6 +21,7 @@
package org.zanata.dao;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
@@ -54,9 +55,13 @@
import org.zanata.model.HDocument;
import org.zanata.model.HLocale;
import org.zanata.model.HTextFlow;
+import org.zanata.util.HTextFlowPosComparator;
+import org.zanata.webtrans.shared.model.DocumentId;
import org.zanata.webtrans.shared.model.TransMemoryQuery;
import org.zanata.webtrans.shared.rpc.HasSearchType.SearchType;
+import com.google.common.collect.Lists;
+
import lombok.extern.slf4j.Slf4j;
@Name("textFlowDAO")
@@ -65,6 +70,7 @@
@Slf4j
public class TextFlowDAO extends AbstractDAOImpl<HTextFlow, Long>
{
+ //TODO replace all getSession() code to use entityManager
private static final Version LUCENE_VERSION = Version.LUCENE_29;
@In
@@ -237,7 +243,7 @@ public int getCountByDocument(Long documentId)
}
@SuppressWarnings("unchecked")
- public List<HTextFlow> getTransUnitList(Long documentId)
+ public List<HTextFlow> getTextFlows(Long documentId)
{
Query q = getSession().createQuery("from HTextFlow tf where tf.obsolete=0 and tf.document.id = :id order by tf.pos");
q.setParameter("id", documentId);
@@ -288,20 +294,18 @@ public int compare(Long arg0, Long arg1)
* @param hLocale locale
* @return a list of HTextFlow that has no translation for given locale.
*/
- public List<HTextFlow> getAllUntranslatedTextFlowByDocumentId(Long documentId, HLocale hLocale)
+ public List<HTextFlow> getAllUntranslatedTextFlowByDocumentId(DocumentId documentId, HLocale hLocale)
{
// @formatter:off
String query = "select distinct tf from HTextFlow tf left join tf.targets " +
"where tf.obsolete = 0 and tf.document.id = :docId and " +
"(:locale not in indices(tf.targets) or exists " + //text flow does not have a target for given locale
- " (select tft.id from HTextFlowTarget tft where tft.textFlow.id = tf.id and tft.locale = :locale and " +
- " (size(tft.contents) = 0 or tft.state = :contentState)" +
- " )" + //text flow has target but target has either empty contents or content state is NEW
+ " (select tft.id from HTextFlowTarget tft where tft.textFlow.id = tf.id and tft.locale = :locale and tft.state = :contentState)" + //text flow has target but target has either empty contents or content state is NEW
") order by tf.pos";
// @formatter:on
Query textFlowQuery = getSession().createQuery(query);
- textFlowQuery.setParameter("docId", documentId);
+ textFlowQuery.setParameter("docId", documentId.getId());
textFlowQuery.setParameter("locale", hLocale);
textFlowQuery.setParameter("contentState", ContentState.New);
textFlowQuery.setCacheable(true).setComment("TextFlowDAO.getAllUntranslatedTextFlowByDocId");
@@ -312,4 +316,49 @@ public int compare(Long arg0, Long arg1)
new Object [] { documentId, result.size(), hLocale.getLocaleId()});
return result;
}
+
+ public List<HTextFlow> getTextFlowsByStatus(DocumentId documentId, HLocale hLocale, boolean filterTranslated, boolean filterNeedReview, boolean filterUntranslated)
+ {
+ List<HTextFlow> result = Lists.newArrayList();
+ List<HTextFlow> untranslated = Lists.newArrayList();
+ List<HTextFlow> translated = Lists.newArrayList();
+
+ if (filterUntranslated)
+ {
+ //hard part. leave it alone.
+ untranslated = getAllUntranslatedTextFlowByDocumentId(documentId, hLocale);
+ result.addAll(untranslated);
+ }
+ if (filterNeedReview || filterTranslated)
+ {
+ // @formatter:off
+ String queryString = "select distinct tf from HTextFlow tf inner join tf.targets as tft " +
+ "where tf.document.id = :docId and tft.locale = :locale and tft.state in (:contentStates) " +
+ "order by tf.pos";
+ // @formatter:on
+ List<ContentState> contentStates = Lists.newArrayList();
+ if (filterNeedReview)
+ {
+ contentStates.add(ContentState.NeedReview);
+ }
+ if (filterTranslated)
+ {
+ contentStates.add(ContentState.Approved);
+ }
+ Query query = getSession().createQuery(queryString);
+ query.setParameter("docId", documentId.getId());
+ query.setParameter("locale", hLocale);
+ query.setParameterList("contentStates", contentStates);
+ query.setCacheable(true).setComment("TextFlowDAO.getTextFlowsByStatus");
+
+ translated = query.list();
+ result.addAll(translated);
+ }
+
+ if (!untranslated.isEmpty() && !translated.isEmpty())
+ {
+ Collections.sort(result, HTextFlowPosComparator.INSTANCE);
+ }
+ return result;
+ }
}
@@ -21,6 +21,7 @@
package org.zanata.service.impl;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
@@ -39,17 +40,16 @@
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.In;
-import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
-import org.jboss.seam.log.Log;
import org.zanata.common.ContentState;
import org.zanata.common.LocaleId;
import org.zanata.dao.DocumentDAO;
import org.zanata.dao.TextFlowDAO;
import org.zanata.exception.ZanataServiceException;
import org.zanata.hibernate.search.ConfigurableNgramAnalyzer;
import org.zanata.hibernate.search.IndexFieldLabels;
+import org.zanata.model.HDocument;
import org.zanata.model.HLocale;
import org.zanata.model.HTextFlow;
import org.zanata.model.HTextFlowTarget;
@@ -58,7 +58,8 @@
import org.zanata.service.TextFlowSearchService;
import org.zanata.webtrans.shared.model.DocumentId;
import org.zanata.webtrans.shared.model.WorkspaceId;
-import org.zanata.webtrans.shared.util.TextFlowFilter;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
@@ -82,9 +83,6 @@
DocumentDAO documentDAO;
@In
- TextFlowFilter textFlowFilterImpl;
-
- @In
private FullTextEntityManager entityManager;
@Override
@@ -129,14 +127,14 @@
if (!constraints.isSearchInSource() && !constraints.isSearchInTarget())
{
//searching nowhere
- return new ArrayList<HTextFlowTarget>();
+ return Collections.emptyList();
}
// FIXME remove .trim() and zero-length check when ngram analyzer is updated to respect leading and trailing whitespace
int searchLength = Math.min(3, constraints.getSearchString().trim().length());
if (searchLength == 0)
{
- return new ArrayList<HTextFlowTarget>();
+ return Collections.emptyList();
}
Analyzer ngramAnalyzer = new ConfigurableNgramAnalyzer(searchLength, !constraints.isCaseSensitive());
@@ -231,7 +229,126 @@
@Override
public List<HTextFlow> findTextFlows(WorkspaceId workspace, DocumentId doc, FilterConstraints constraints)
{
- // TODO Implement findTextFlows within document
- return null;
+ //TODO this method has high percentage of duplication from the above method. Refactor.
+ LocaleId localeId = workspace.getLocaleId();
+ String projectSlug = workspace.getProjectIterationId().getProjectSlug();
+ String iterationSlug = workspace.getProjectIterationId().getIterationSlug();
+
+ localeServiceImpl.validateLocaleByProjectIteration(localeId, projectSlug, iterationSlug);
+
+ if (!constraints.isSearchInSource() && !constraints.isSearchInTarget())
+ {
+ //searching nowhere
+ return Collections.emptyList();
+ }
+
+ // FIXME remove .trim() and zero-length check when ngram analyzer is updated to respect leading and trailing whitespace
+ int searchLength = Math.min(3, constraints.getSearchString().trim().length());
+ if (searchLength == 0)
+ {
+ return Collections.emptyList();
+ }
+ Analyzer ngramAnalyzer = new ConfigurableNgramAnalyzer(searchLength, !constraints.isCaseSensitive());
+
+ String[] searchFields = (constraints.isCaseSensitive() ? IndexFieldLabels.CONTENT_FIELDS_CASE_PRESERVED : IndexFieldLabels.CONTENT_FIELDS_CASE_FOLDED);
+
+ Query searchPhraseQuery;
+ QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_29, searchFields, ngramAnalyzer);
+ try
+ {
+ searchPhraseQuery = parser.parse("\"" + QueryParser.escape(constraints.getSearchString()) + "\"");
+ }
+ catch (ParseException e)
+ {
+ throw new ZanataServiceException("Failed to parse query", e);
+ }
+
+ TermQuery projectQuery = new TermQuery(new Term(IndexFieldLabels.PROJECT_FIELD, projectSlug));
+ TermQuery iterationQuery = new TermQuery(new Term(IndexFieldLabels.ITERATION_FIELD, iterationSlug));
+ TermQuery localeQuery = new TermQuery(new Term(IndexFieldLabels.LOCALE_ID_FIELD, localeId.getId()));
+ HDocument hDocument = documentDAO.getById(doc.getId());
+ TermQuery documentQuery = new TermQuery(new Term(IndexFieldLabels.DOCUMENT_ID_FIELD, hDocument.getDocId()));
+
+ BooleanQuery sourceQuery = new BooleanQuery();
+ sourceQuery.add(projectQuery, Occur.MUST);
+ sourceQuery.add(iterationQuery, Occur.MUST);
+ sourceQuery.add(searchPhraseQuery, Occur.MUST);
+ sourceQuery.add(documentQuery, Occur.MUST);
+
+ List<HTextFlow> resultList = Lists.newArrayList();
+ if (constraints.isSearchInTarget())
+ {
+ BooleanQuery targetQuery = (BooleanQuery) sourceQuery.clone();
+ targetQuery.add(localeQuery, Occur.MUST);
+ if (!constraints.isIncludeApproved())
+ {
+ TermQuery approvedStateQuery = new TermQuery(new Term(IndexFieldLabels.CONTENT_STATE_FIELD, ContentState.Approved.toString()));
+ targetQuery.add(approvedStateQuery, Occur.MUST_NOT);
+ }
+
+ if (!constraints.isIncludeFuzzy())
+ {
+ TermQuery approvedStateQuery = new TermQuery(new Term(IndexFieldLabels.CONTENT_STATE_FIELD, ContentState.NeedReview.toString()));
+ targetQuery.add(approvedStateQuery, Occur.MUST_NOT);
+ }
+
+ if (!constraints.isIncludeNew())
+ {
+ TermQuery approvedStateQuery = new TermQuery(new Term(IndexFieldLabels.CONTENT_STATE_FIELD, ContentState.New.toString()));
+ targetQuery.add(approvedStateQuery, Occur.MUST_NOT);
+ }
+
+ FullTextQuery ftQuery = entityManager.createFullTextQuery(targetQuery, HTextFlowTarget.class);
+ @SuppressWarnings("unchecked")
+ List<HTextFlowTarget> matchedTargets = (List<HTextFlowTarget>) ftQuery.getResultList();
+ log.info("got {} HTextFLowTarget results", matchedTargets.size());
+ List<HTextFlow> hTextFlows = Lists.transform(matchedTargets, new Function<HTextFlowTarget, HTextFlow>()
+ {
+ @Override
+ public HTextFlow apply(HTextFlowTarget target)
+ {
+ return target.getTextFlow();
+ }
+ });
+ resultList.addAll(hTextFlows);
+ }
+
+ if (constraints.isSearchInSource())
+ {
+ FullTextQuery ftQuery = entityManager.createFullTextQuery(sourceQuery, HTextFlow.class);
+ @SuppressWarnings("unchecked")
+ List<HTextFlow> matchedSources = (List<HTextFlow>) ftQuery.getResultList();
+ log.info("got {} HTextFLow results", matchedSources.size());
+ HLocale hLocale = localeServiceImpl.getByLocaleId(localeId);
+ for (HTextFlow hTextFlow : matchedSources)
+ {
+ if (!resultList.contains(hTextFlow))
+ {
+ HTextFlowTarget hTextFlowTarget = hTextFlow.getTargets().get(hLocale.getId());
+ if (isContentStateValid(hTextFlowTarget, constraints))
+ {
+ resultList.add(hTextFlow);
+ }
+ }
+ }
+ }
+
+ return resultList;
+ }
+
+ private static boolean isContentStateValid(HTextFlowTarget hTextFlowTarget, FilterConstraints constraints)
+ {
+ if (hTextFlowTarget == null)
+ {
+ return constraints.isIncludeNew();
+ }
+ else
+ {
+ ContentState state = hTextFlowTarget.getState();
+ return (constraints.isIncludeApproved() && state == ContentState.Approved) ||
+ (constraints.isIncludeFuzzy() && state == ContentState.NeedReview) ||
+ (constraints.isIncludeNew() && state == ContentState.New);
+ }
}
+
}
@@ -0,0 +1,19 @@
+package org.zanata.util;
+
+import java.util.Comparator;
+
+import org.zanata.model.HTextFlow;
+
+/**
+* @author Patrick Huang <a href="mailto:pahuang@redhat.com">pahuang@redhat.com</a>
+*/
+public enum HTextFlowPosComparator implements Comparator<HTextFlow>
+{
+ INSTANCE;
+
+ @Override
+ public int compare(HTextFlow one, HTextFlow other)
+ {
+ return one.getPos().compareTo(other.getPos());
+ }
+}
@@ -28,6 +28,7 @@
import org.zanata.webtrans.client.history.History;
import org.zanata.webtrans.client.history.HistoryToken;
+import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.HasValue;
@@ -50,7 +51,7 @@ public TransFilterPresenter(final Display display, final EventBus eventBus, fina
{
super(display, eventBus);
this.history = history;
- currentState = new HistoryToken();;
+ currentState = new HistoryToken();
}
@Override
@@ -62,7 +63,7 @@ protected void onBind()
@Override
public void onValueChange(ValueChangeEvent<String> event)
{
- if (event.getValue() != currentState.getSearchText())
+ if (!event.getValue().equals(currentState.getSearchText()))
{
HistoryToken newToken = history.getHistoryToken();
newToken.setSearchText(event.getValue());
@@ -78,10 +79,10 @@ public void onValueChange(ValueChangeEvent<String> event)
public void onValueChange(ValueChangeEvent<String> event)
{
HistoryToken token = history.getHistoryToken();
- if (token.getSearchText() != currentState.getSearchText())
+ if (!token.getSearchText().equals(currentState.getSearchText()))
{
- eventBus.fireEvent(new FindMessageEvent(token.getSearchText()));
display.getFilterText().setValue(token.getSearchText(), false);
+ eventBus.fireEvent(new FindMessageEvent(token.getSearchText()));
}
currentState = token;
}
Oops, something went wrong.

0 comments on commit 722b5d8

Please sign in to comment.