Add delete all with this query

This commit is contained in:
Kaoru FUZITA 2015-11-25 07:02:09 +09:00
parent 4458381e54
commit 2ff1031e43
16 changed files with 229 additions and 86 deletions

View file

@ -296,6 +296,8 @@ public class Constants extends CoreLibConstants {
public static final String FACET_QUERY_PREFIX = "query:";
public static final String MATCHES_ALL_QUERY = "*:*";
public static final String FESS_ES_TRANSPORT_ADDRESSES = "fess.es.transport_addresses";
public static final String FESS_ES_CLUSTER_NAME = "fess.es.cluster_name";

View file

@ -36,6 +36,7 @@ import org.codelibs.core.lang.StringUtil;
import org.codelibs.core.misc.DynamicProperties;
import org.codelibs.fess.Constants;
import org.codelibs.fess.app.web.base.login.FessLoginAssist;
import org.codelibs.fess.entity.QueryContext;
import org.codelibs.fess.entity.SearchRenderData;
import org.codelibs.fess.entity.SearchRequestParams;
import org.codelibs.fess.es.client.FessEsClient;
@ -195,6 +196,41 @@ public class SearchService {
}
}
public int deleteByQuery(final HttpServletRequest request, final SearchRequestParams params) {
if (StringUtil.isNotBlank(params.getOperator())) {
request.setAttribute(Constants.DEFAULT_OPERATOR, params.getOperator());
}
final StringBuilder queryBuf = new StringBuilder(255);
if (StringUtil.isNotBlank(params.getQuery())) {
if (params.getQuery().indexOf(" OR ") >= 0) {
queryBuf.append('(').append(params.getQuery()).append(')');
} else {
queryBuf.append(params.getQuery());
}
}
if (params.getAdditional() != null) {
appendAdditionalQuery(params.getAdditional(), additional -> {
queryBuf.append(' ').append(additional);
});
}
params.getFields().entrySet().stream().forEach(entry -> {
appendQueries(queryBuf, entry.getKey(), entry.getValue());
});
if (params.getLanguages() != null) {
appendQueries(queryBuf, fessConfig.getIndexFieldLang(), params.getLanguages());
}
final String query = queryBuf.toString().trim();
final QueryContext queryContext = queryHelper.build(query, context -> {
context.skipRoleQuery();
});
return fessEsClient.deleteByQuery(fessConfig.getIndexDocumentIndex(), fessConfig.getIndexDocumentType(),
queryContext.getQueryBuilder());
}
protected void storeSearchLog(final HttpServletRequest request, final LocalDateTime requestedTime, final String queryId,
final String query, final int pageStart, final int pageSize, final QueryResponseList queryResponseList) {

View file

@ -22,6 +22,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.codelibs.core.lang.StringUtil;
import org.codelibs.fess.Constants;
import org.codelibs.fess.app.service.SearchService;
import org.codelibs.fess.app.web.base.FessAdminAction;
import org.codelibs.fess.entity.SearchRenderData;
@ -109,19 +110,19 @@ public class AdminSearchlistAction extends FessAdminAction {
// ==============
@Execute
public HtmlResponse index(final ListForm form) {
saveToken();
validate(form, messages -> {}, () -> asHtml(path_AdminError_AdminErrorJsp));
return asHtml(path_AdminSearchlist_AdminSearchlistJsp);
return asListHtml();
}
protected HtmlResponse doSearch(final ListForm form) {
validate(form, messages -> {}, () -> asHtml(path_AdminSearchlist_AdminSearchlistJsp));
validate(form, messages -> {}, () -> asListHtml());
if (StringUtil.isBlank(form.query)) {
// redirect to index page
form.query = null;
return redirect(getClass());
// query matches on all documents.
form.query = Constants.MATCHES_ALL_QUERY;
}
return asHtml(path_AdminSearchlist_AdminSearchlistJsp).renderWith(data -> {
return asListHtml().renderWith(data -> {
doSearchInternal(data, form);
});
}
@ -135,7 +136,7 @@ public class AdminSearchlistAction extends FessAdminAction {
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
}
throwValidationError(e.getMessageCode(), () -> asHtml(path_AdminSearchlist_AdminSearchlistJsp));
throwValidationError(e.getMessageCode(), () -> asListHtml());
} catch (final ResultOffsetExceededException e) {
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
@ -148,21 +149,25 @@ public class AdminSearchlistAction extends FessAdminAction {
@Execute
public HtmlResponse search(final ListForm form) {
saveToken();
return doSearch(form);
}
@Execute
public HtmlResponse prev(final ListForm form) {
saveToken();
return doMove(form, -1);
}
@Execute
public HtmlResponse next(final ListForm form) {
saveToken();
return doMove(form, 1);
}
@Execute
public HtmlResponse move(final ListForm form) {
saveToken();
return doMove(form, 0);
}
@ -185,27 +190,53 @@ public class AdminSearchlistAction extends FessAdminAction {
@Execute
public HtmlResponse delete(final DeleteForm form) {
validate(form, messages -> {}, () -> asHtml(path_AdminSearchlist_AdminSearchlistJsp));
verifyToken(() -> asListHtml());
validate(form, messages -> {}, () -> asListHtml());
final String docId = form.docId;
if (jobHelper.isCrawlProcessRunning()) {
throwValidationError(messages -> messages.addErrorsCannotDeleteDocBecauseOfRunning(GLOBAL),
() -> asHtml(path_AdminSearchlist_AdminSearchlistJsp));
throwValidationError(messages -> messages.addErrorsCannotDeleteDocBecauseOfRunning(GLOBAL), () -> asListHtml());
}
try {
final QueryBuilder query = QueryBuilders.termQuery(fessConfig.getIndexFieldDocId(), docId);
fessEsClient.deleteByQuery(fessConfig.getIndexDocumentIndex(), fessConfig.getIndexDocumentType(), query);
saveInfo(messages -> messages.addSuccessDeleteDocFromIndex(GLOBAL));
} catch (final Exception e) {
throwValidationError(messages -> messages.addErrorsFailedToDeleteDocInAdmin(GLOBAL),
() -> asHtml(path_AdminSearchlist_AdminSearchlistJsp));
throwValidationError(messages -> messages.addErrorsFailedToDeleteDocInAdmin(GLOBAL), () -> asListHtml());
}
return redirectWith(getClass(), moreUrl("search").params("query", form.query));
return asListHtml();
}
@Execute
public HtmlResponse deleteall(final ListForm form) {
verifyToken(() -> asListHtml());
validate(form, messages -> {}, () -> asListHtml());
if (jobHelper.isCrawlProcessRunning()) {
throwValidationError(messages -> messages.addErrorsCannotDeleteDocBecauseOfRunning(GLOBAL), () -> asListHtml());
}
try {
searchService.deleteByQuery(request, form);
saveInfo(messages -> messages.addSuccessDeleteDocFromIndex(GLOBAL));
} catch (final InvalidQueryException e) {
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
}
throwValidationError(e.getMessageCode(), () -> asListHtml());
}
return asListHtml();
}
public boolean isSolrProcessRunning() {
return jobHelper.isCrawlProcessRunning();
}
// ===================================================================================
// JSP
// =========
private HtmlResponse asListHtml() {
return asHtml(path_AdminSearchlist_AdminSearchlistJsp);
}
protected static class WebRenderData extends SearchRenderData {
private final RenderData data;

View file

@ -654,7 +654,7 @@ public abstract class EsAbstractConditionBean implements ConditionBean {
if (searchType != null) {
builder.setSearchType(searchType);
}
if (timeoutInMillis != -1) {
if (timeoutInMillis == -1) {
builder.setTimeout(new TimeValue(timeoutInMillis));
}
if (version != null) {

View file

@ -164,7 +164,6 @@ public abstract class EsAbstractConditionQuery implements ConditionQuery {
filterList.forEach(query -> {
boolQuery.filter(query);
});
regQ(boolQuery);
return boolQuery;
}

View file

@ -654,7 +654,7 @@ public abstract class EsAbstractConditionBean implements ConditionBean {
if (searchType != null) {
builder.setSearchType(searchType);
}
if (timeoutInMillis != -1) {
if (timeoutInMillis == -1) {
builder.setTimeout(new TimeValue(timeoutInMillis));
}
if (version != null) {

View file

@ -164,7 +164,6 @@ public abstract class EsAbstractConditionQuery implements ConditionQuery {
filterList.forEach(query -> {
boolQuery.filter(query);
});
regQ(boolQuery);
return boolQuery;
}

View file

@ -654,7 +654,7 @@ public abstract class EsAbstractConditionBean implements ConditionBean {
if (searchType != null) {
builder.setSearchType(searchType);
}
if (timeoutInMillis != -1) {
if (timeoutInMillis == -1) {
builder.setTimeout(new TimeValue(timeoutInMillis));
}
if (version != null) {

View file

@ -164,7 +164,6 @@ public abstract class EsAbstractConditionQuery implements ConditionQuery {
filterList.forEach(query -> {
boolQuery.filter(query);
});
regQ(boolQuery);
return boolQuery;
}

View file

@ -40,6 +40,7 @@ import org.apache.lucene.queryparser.ext.ExtendableQueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
@ -299,6 +300,8 @@ public class QueryHelper implements Serializable {
} else if (query instanceof BooleanQuery) {
final BooleanQuery booleanQuery = (BooleanQuery) query;
return convertBooleanQuery(context, booleanQuery);
} else if (query instanceof MatchAllDocsQuery) {
return QueryBuilders.matchAllQuery();
}
throw new InvalidQueryException(messages -> messages.addErrorsInvalidQueryUnknown(ActionMessages.GLOBAL_PROPERTY_KEY),
"Unknown query: " + query.getClass() + " => " + query);

View file

@ -1488,13 +1488,19 @@ public class FessLabels extends ActionMessages {
public static final String LABELS_search_list_configuration = "{labels.search_list_configuration}";
/** The key of the message: Delete */
public static final String LABELS_search_list_delete_link = "{labels.search_list_delete_link}";
public static final String LABELS_search_list_button_delete = "{labels.search_list_button_delete}";
/** The key of the message: Do you really want to delete? */
public static final String LABELS_search_list_delete_confirmation = "{labels.search_list_delete_confirmation}";
/** The key of the message: Delete all with this query */
public static final String LABELS_search_list_button_delete_all = "{labels.search_list_button_delete_all}";
/** The key of the message: Do you really want to delete all with this query? */
public static final String LABELS_search_list_delete_all_confirmation = "{labels.search_list_delete_all_confirmation}";
/** The key of the message: Cancel */
public static final String LABELS_search_list_delete_cancel = "{labels.search_list_delete_cancel}";
/** The key of the message: Do you really want to delete? ({0}) */
public static final String LABELS_search_list_delete_confirmation = "{labels.search_list_delete_confirmation}";
public static final String LABELS_search_list_button_cancel = "{labels.search_list_button_cancel}";
/** The key of the message: Failure URL */
public static final String LABELS_failure_url_configuration = "{labels.failure_url_configuration}";

View file

@ -493,9 +493,11 @@ labels.wizard_start_crawling_desc=To click "Start Crawling" button, you can star
labels.wizard_button_start_crawling=Start Crawling
labels.wizard_button_finish=Skip
labels.search_list_configuration=Search
labels.search_list_delete_link=Delete
labels.search_list_delete_cancel=Cancel
labels.search_list_delete_confirmation=Do you really want to delete? ({0})
labels.search_list_button_delete=Delete
labels.search_list_delete_confirmation=Do you really want to delete?
labels.search_list_button_delete_all=Delete all with this query
labels.search_list_delete_all_confirmation=Do you really want to delete all with this query?
labels.search_list_button_cancel=Cancel
labels.failure_url_configuration=Failure URL
labels.failure_url_search_url=URL
labels.failure_url_search_error_count=Error Count

View file

@ -55,7 +55,8 @@
styleClass="form-control" placeholder="${ph_session_id}"></la:text>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" name="search"
<button type="submit" class="btn btn-primary" id="submit"
name="search"
value="<la:message key="labels.crawling_session_search" />">
<i class="fa fa-search"></i>
<la:message key="labels.crawling_session_search" />

View file

@ -70,7 +70,8 @@
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" name="search"
<button type="submit" class="btn btn-primary" id="submit"
name="search"
value="<la:message key="labels.crud_button_search" />">
<i class="fa fa-search"></i>
<la:message key="labels.crud_button_search" />

View file

@ -51,8 +51,8 @@
placeholder="Type a search query" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" name="search"
value="<la:message key="labels.search"/>">
<button type="submit" class="btn btn-primary" id="submit"
name="search" value="<la:message key="labels.search"/>">
<i class="fa fa-search"></i>
<la:message key="labels.search" />
</button>
@ -83,60 +83,17 @@
<a href="${doc.urlLink}">${f:h(doc.contentTitle)}</a>
</h3>
<div class="body col-sm-11">
${doc.contentDescription}</div> <c:if
test="${!crawlerProcessRunning}">
<button type="button"
class="btn btn-xs btn-danger col-sm-1"
data-toggle="modal" data-target="#confirmToDelete">
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_delete_link" />
</button>
<div class="modal modal-danger fade" id="confirmToDelete"
tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"
data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
<la:message key="labels.search_list_delete_link" />
</h4>
</div>
<div class="modal-body">
<p>
<la:message
key="labels.search_list_delete_confirmation"
arg0="${f:h(doc.urlLink)}" />
</p>
</div>
<div class="modal-footer">
<button type="button"
class="btn btn-outline pull-left"
data-dismiss="modal">
<la:message key="labels.search_list_delete_cancel" />
</button>
<la:form action="delete">
<%-- TODO: doc_id --%>
<la:hidden property="docId"
value="${f:u(doc.doc_id)}" />
<la:hidden property="query" value="${f:u(query)}" />
<button type="submit"
class="btn btn-outline btn-danger">
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_delete_link" />
</button>
</la:form>
</div>
</div>
</div>
</div>
</c:if> <c:if test="${crawlerProcessRunning}">
<div class="col-sm-1">
<la:message key="labels.search_list_delete_link" />
</div>
</c:if>
${doc.contentDescription}</div>
<button type="button"
class="btn btn-xs btn-danger col-sm-1"
data-toggle="modal" data-target="#confirmToDelete"
data-docid="${f:u(doc.doc_id)}"
data-title="${f:h(doc.contentTitle)}"
data-url="${f:h(doc.urlLink)}"
<c:if test="${crawlerProcessRunning}">disable</c:if>>
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_button_delete" />
</button>
</li>
</c:forEach>
</ol>
@ -189,8 +146,99 @@
</div>
</c:otherwise>
</c:choose>
<div class="modal modal-danger fade" id="confirmToDelete"
tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
<la:message key="labels.search_list_button_delete" />
</h4>
</div>
<div class="modal-body">
<p>
<la:message key="labels.search_list_delete_confirmation" />
</p>
<p>
<strong id="delete-doc-title"></strong><br /> <span
id="delete-doc-url"></span>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline pull-left"
data-dismiss="modal">
<la:message key="labels.search_list_button_cancel" />
</button>
<la:form action="/admin/searchlist/delete">
<input type="hidden" name="docId" id="docId" />
<button type="submit" class="btn btn-outline btn-danger"
name="delete"
value="<la:message key="labels.search_list_button_delete" />">
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_button_delete" />
</button>
</la:form>
</div>
</div>
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<c:if test="${f:h(allRecordCount) > 0}">
<div class="row">
<div class="col-sm-12 center">
<button type="button" class="btn btn-danger"
data-toggle="modal" data-target="#confirmToDeleteAll">
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_button_delete_all" />
</button>
</div>
<div class="modal modal-danger fade" id="confirmToDeleteAll"
tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
<la:message key="labels.search_list_button_delete_all" />
</h4>
</div>
<div class="modal-body">
<p>
<la:message
key="labels.search_list_delete_all_confirmation" />
</p>
</div>
<div class="modal-footer">
<la:form action="/admin/searchlist/deleteall">
<la:hidden property="query" />
<button type="button" class="btn btn-outline pull-left"
data-dismiss="modal">
<la:message key="labels.search_list_button_cancel" />
</button>
<button type="submit" class="btn btn-outline btn-danger"
name="deleteall"
value="<la:message key="labels.search_list_button_delete_all" />">
<i class="fa fa-trash"></i>
<la:message key="labels.search_list_button_delete_all" />
</button>
</la:form>
</div>
</div>
</div>
</div>
</div>
</c:if>
</div>
<!-- /.box-footer -->
</div>
<!-- /.box -->
</div>

View file

@ -1,8 +1,13 @@
$(function() {
$('input[type="text"],select', '.login-box,section.content').first().focus();
$('input[type="text"],select', '.login-box,section.content').first()
.focus();
$("section.content input").keypress(function(e) {
if (e.which == 13) {
var $submitButton = $('input#submit, button#submit');
if ($submitButton.size() > 0) {
$submitButton[0].submit();
}
// ignore enter key down
return false;
}
@ -17,4 +22,15 @@ $(function() {
document.location = $(this).attr('data-href');
});
});
$('#confirmToDelete').on('show.bs.modal', function(event) {
var button = $(event.relatedTarget);
var docId = button.data('docid');
var title = button.data('title');
var url = button.data('url');
$(this).find('.modal-body #delete-doc-title').text(title);
$(this).find('.modal-body #delete-doc-url').text(url);
$(this).find('.modal-footer input#docId').val(docId);
})
});