From 4f8076427b9f017ee845bad5ab8e5e0df4a4c6be Mon Sep 17 00:00:00 2001
From: jendib
Date: Sun, 18 Aug 2013 13:02:50 +0200
Subject: [PATCH] Search criterias on full content and specific date
---
.../docs/core/dao/jpa/DocumentDao.java | 4 +-
.../dao/jpa/criteria/DocumentCriteria.java | 23 ++++++
.../docs/core/dao/lucene/LuceneDao.java | 10 ++-
docs-parent/TODO | 6 --
.../docs/rest/resource/DocumentResource.java | 31 +++++++-
.../webapp/partial/docs/document.edit.html | 2 +-
.../main/webapp/partial/docs/document.html | 11 ++-
.../webapp/partial/docs/document.view.html | 2 +-
.../main/webapp/partial/docs/file.view.html | 6 +-
.../main/webapp/partial/share/file.view.html | 6 +-
.../src/main/webapp/partial/share/share.html | 2 +-
.../docs/rest/TestDocumentResource.java | 74 ++++++++++++++-----
12 files changed, 133 insertions(+), 44 deletions(-)
diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java
index 2b27faa8..944592e1 100644
--- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java
+++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java
@@ -154,9 +154,9 @@ public class DocumentDao {
criteriaList.add("d.DOC_IDUSER_C = :userId");
parameterMap.put("userId", criteria.getUserId());
}
- if (!Strings.isNullOrEmpty(criteria.getSearch())) {
+ if (!Strings.isNullOrEmpty(criteria.getSearch()) || !Strings.isNullOrEmpty(criteria.getFullSearch())) {
LuceneDao luceneDao = new LuceneDao();
- Set documentIdList = luceneDao.search(criteria.getUserId(), criteria.getSearch());
+ Set documentIdList = luceneDao.search(criteria.getUserId(), criteria.getSearch(), criteria.getFullSearch());
if (documentIdList.size() == 0) {
// If the search doesn't find any document, the request should return nothing
documentIdList.add(UUID.randomUUID().toString());
diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java
index 2b61b339..a3c26997 100644
--- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java
+++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java
@@ -20,6 +20,11 @@ public class DocumentCriteria {
*/
private String search;
+ /**
+ * Full content search query.
+ */
+ private String fullSearch;
+
/**
* Minimum creation date.
*/
@@ -81,6 +86,24 @@ public class DocumentCriteria {
this.search = search;
}
+ /**
+ * Getter of fullSearch.
+ *
+ * @return the fullSearch
+ */
+ public String getFullSearch() {
+ return fullSearch;
+ }
+
+ /**
+ * Setter of fullSearch.
+ *
+ * @param fullSearch fullSearch
+ */
+ public void setFullSearch(String fullSearch) {
+ this.fullSearch = fullSearch;
+ }
+
/**
* Getter of createDateMin.
*
diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java
index e5a12b5f..6856e166 100644
--- a/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java
+++ b/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java
@@ -143,13 +143,15 @@ public class LuceneDao {
* Search files.
*
* @param userId User ID to filter on
- * @param searchQuery Search query
+ * @param searchQuery Search query on title and description
+ * @param fullSearchQuery Search query on all fields
* @return List of document IDs
* @throws Exception
*/
- public Set search(String userId, String searchQuery) throws Exception {
+ public Set search(String userId, String searchQuery, String fullSearchQuery) throws Exception {
// Escape query and add quotes so QueryParser generate a PhraseQuery
- searchQuery = "\"" + QueryParserUtil.escape(searchQuery) + "\"";
+ searchQuery = "\"" + QueryParserUtil.escape(searchQuery + " " + fullSearchQuery) + "\"";
+ fullSearchQuery = "\"" + QueryParserUtil.escape(fullSearchQuery) + "\"";
// Build search query
StandardQueryParser qpHelper = new StandardQueryParser(new DocsStandardAnalyzer(Version.LUCENE_42));
@@ -157,9 +159,9 @@ public class LuceneDao {
// Search on documents and files
BooleanQuery query = new BooleanQuery();
- query.add(qpHelper.parse(searchQuery, "content"), Occur.SHOULD);
query.add(qpHelper.parse(searchQuery, "title"), Occur.SHOULD);
query.add(qpHelper.parse(searchQuery, "description"), Occur.SHOULD);
+ query.add(qpHelper.parse(fullSearchQuery, "content"), Occur.SHOULD);
// Filter on provided user ID
List terms = new ArrayList();
diff --git a/docs-parent/TODO b/docs-parent/TODO
index d57cb696..a0c153ff 100644
--- a/docs-parent/TODO
+++ b/docs-parent/TODO
@@ -1,8 +1,2 @@
-- New image rescale between thumbnail and original (client)
-- Criteria to search inside OCR-ed content (eg. full:uranium) (server)
-- Criteria to search on a specific time span (eg. at:2013-06) (server)
-- Show help on special criterias (client)
-- Disable Add/Edit button while uploading (client)
-
- Extract text from PDF for indexing, see PDFBox (server)
- Make thumbnail of the first page of PDF, see PDFBox (server)
\ No newline at end of file
diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java
index 4985bf95..533d314b 100644
--- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java
+++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java
@@ -207,10 +207,14 @@ public class DocumentResource extends BaseResource {
DateTimeFormat.forPattern("yyyy").getParser(),
DateTimeFormat.forPattern("yyyy-MM").getParser(),
DateTimeFormat.forPattern("yyyy-MM-dd").getParser() };
+ DateTimeFormatter yearFormatter = new DateTimeFormatter(null, parsers[0]);
+ DateTimeFormatter monthFormatter = new DateTimeFormatter(null, parsers[1]);
+ DateTimeFormatter dayFormatter = new DateTimeFormatter(null, parsers[2]);
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter();
String[] criteriaList = search.split(" *");
List query = new ArrayList<>();
+ List fullQuery = new ArrayList<>();
for (String criteria : criteriaList) {
String[] params = criteria.split(":");
if (params.length != 2 || Strings.isNullOrEmpty(params[0]) || Strings.isNullOrEmpty(params[1])) {
@@ -233,7 +237,7 @@ public class DocumentResource extends BaseResource {
documentCriteria.getTagIdList().add(tag.getId());
}
} else if (params[0].equals("after") || params[0].equals("before")) {
- // New date criteria
+ // New date span criteria
try {
DateTime date = formatter.parseDateTime(params[1]);
if (params[0].equals("before")) documentCriteria.setCreateDateMax(date.toDate());
@@ -241,22 +245,45 @@ public class DocumentResource extends BaseResource {
} catch (IllegalArgumentException e) {
// NOP
}
+ } else if (params[0].equals("at")) {
+ // New specific date criteria
+ try {
+ if (params[1].length() == 10) {
+ DateTime date = dayFormatter.parseDateTime(params[1]);
+ documentCriteria.setCreateDateMin(date.toDate());
+ documentCriteria.setCreateDateMax(date.plusDays(1).toDate());
+ } else if (params[1].length() == 7) {
+ DateTime date = monthFormatter.parseDateTime(params[1]);
+ documentCriteria.setCreateDateMin(date.toDate());
+ documentCriteria.setCreateDateMax(date.plusMonths(1).toDate());
+ } else if (params[1].length() == 4) {
+ DateTime date = yearFormatter.parseDateTime(params[1]);
+ documentCriteria.setCreateDateMin(date.toDate());
+ documentCriteria.setCreateDateMax(date.plusYears(1).toDate());
+ }
+ } catch (IllegalArgumentException e) {
+ // NOP
+ }
} else if (params[0].equals("shared")) {
// New shared state criteria
if (params[1].equals("yes")) {
documentCriteria.setShared(true);
}
} else if (params[0].equals("lang")) {
- // New shared state criteria
+ // New language criteria
if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) {
documentCriteria.setLanguage(params[1]);
}
+ } else if (params[0].equals("full")) {
+ // New full content search criteria
+ fullQuery.add(params[1]);
} else {
query.add(criteria);
}
}
documentCriteria.setSearch(Joiner.on(" ").join(query));
+ documentCriteria.setFullSearch(Joiner.on(" ").join(fullQuery));
return documentCriteria;
}
diff --git a/docs-web/src/main/webapp/partial/docs/document.edit.html b/docs-web/src/main/webapp/partial/docs/document.edit.html
index 2077ac42..c2fb318e 100644
--- a/docs-web/src/main/webapp/partial/docs/document.edit.html
+++ b/docs-web/src/main/webapp/partial/docs/document.edit.html
@@ -43,7 +43,7 @@
-
+
diff --git a/docs-web/src/main/webapp/partial/docs/document.html b/docs-web/src/main/webapp/partial/docs/document.html
index 0b2e0a67..0b23b2c0 100644
--- a/docs-web/src/main/webapp/partial/docs/document.html
+++ b/docs-web/src/main/webapp/partial/docs/document.html
@@ -7,7 +7,16 @@
-
+
diff --git a/docs-web/src/main/webapp/partial/docs/document.view.html b/docs-web/src/main/webapp/partial/docs/document.view.html
index b26c3dee..df5f8716 100644
--- a/docs-web/src/main/webapp/partial/docs/document.view.html
+++ b/docs-web/src/main/webapp/partial/docs/document.view.html
@@ -25,7 +25,7 @@
-
+
diff --git a/docs-web/src/main/webapp/partial/docs/file.view.html b/docs-web/src/main/webapp/partial/docs/file.view.html
index b99973a2..11cd52ea 100644
--- a/docs-web/src/main/webapp/partial/docs/file.view.html
+++ b/docs-web/src/main/webapp/partial/docs/file.view.html
@@ -9,13 +9,13 @@
-
+
-
+
-
+
diff --git a/docs-web/src/main/webapp/partial/share/file.view.html b/docs-web/src/main/webapp/partial/share/file.view.html
index bd345ebf..0fbb368e 100644
--- a/docs-web/src/main/webapp/partial/share/file.view.html
+++ b/docs-web/src/main/webapp/partial/share/file.view.html
@@ -9,13 +9,13 @@
-
+
-
+
-
+
diff --git a/docs-web/src/main/webapp/partial/share/share.html b/docs-web/src/main/webapp/partial/share/share.html
index b47e649a..e2a1bb37 100644
--- a/docs-web/src/main/webapp/partial/share/share.html
+++ b/docs-web/src/main/webapp/partial/share/share.html
@@ -13,7 +13,7 @@
diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java
index 7c75eff3..b4e38286 100644
--- a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java
+++ b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java
@@ -1,6 +1,20 @@
package com.sismics.docs.rest;
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.util.Date;
+
+import javax.ws.rs.core.MediaType;
+
+import junit.framework.Assert;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.joda.time.format.DateTimeFormat;
+import org.junit.Test;
+
import com.sismics.docs.rest.filter.CookieAuthenticationFilter;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.ClientResponse.Status;
@@ -9,18 +23,6 @@ import com.sun.jersey.core.util.MultivaluedMapImpl;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;
-import junit.framework.Assert;
-import org.codehaus.jettison.json.JSONArray;
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
-import org.junit.Test;
-
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-import java.util.Date;
-
-import javax.ws.rs.core.MediaType;
-
/**
* Exhaustive test of the document resource.
*
@@ -108,20 +110,29 @@ public class TestDocumentResource extends BaseJerseyTest {
Assert.assertEquals("SuperTag", tags.getJSONObject(0).getString("name"));
Assert.assertEquals("#ffff00", tags.getJSONObject(0).getString("color"));
- // Search documents by query
+ // Search documents by query in full content
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
getParams = new MultivaluedMapImpl();
- getParams.putSingle("search", "uranium");
+ getParams.putSingle("search", "full:uranium");
response = documentResource.queryParams(getParams).get(ClientResponse.class);
json = response.getEntity(JSONObject.class);
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
documents = json.getJSONArray("documents");
Assert.assertTrue(documents.length() == 1);
- Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id"));
- Assert.assertEquals(create1Date, documents.getJSONObject(0).getLong("create_date"));
- // Search documents by query
+ // Search documents by query in full content
+ documentResource = resource().path("/document/list");
+ documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
+ getParams = new MultivaluedMapImpl();
+ getParams.putSingle("search", "full:title");
+ response = documentResource.queryParams(getParams).get(ClientResponse.class);
+ json = response.getEntity(JSONObject.class);
+ Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
+ documents = json.getJSONArray("documents");
+ Assert.assertTrue(documents.length() == 1);
+
+ // Search documents by query in title/description
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
getParams = new MultivaluedMapImpl();
@@ -132,7 +143,7 @@ public class TestDocumentResource extends BaseJerseyTest {
documents = json.getJSONArray("documents");
Assert.assertTrue(documents.length() == 1);
- // Search documents by query
+ // Search documents by query in title/description
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
getParams = new MultivaluedMapImpl();
@@ -143,7 +154,19 @@ public class TestDocumentResource extends BaseJerseyTest {
documents = json.getJSONArray("documents");
Assert.assertTrue(documents.length() == 1);
- // Search documents by date
+ // Search documents by specific date
+ documentResource = resource().path("/document/list");
+ documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
+ getParams = new MultivaluedMapImpl();
+ getParams.putSingle("search", "at:" + DateTimeFormat.forPattern("yyyy-MM").print(new Date().getTime()));
+ response = documentResource.queryParams(getParams).get(ClientResponse.class);
+ json = response.getEntity(JSONObject.class);
+ Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
+ documents = json.getJSONArray("documents");
+ Assert.assertTrue(documents.length() == 1);
+ Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id"));
+
+ // Search documents by date span
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
getParams = new MultivaluedMapImpl();
@@ -197,7 +220,7 @@ public class TestDocumentResource extends BaseJerseyTest {
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
getParams = new MultivaluedMapImpl();
- getParams.putSingle("search", "after:2010 before:2040-08 tag:super shared:yes lang:eng uranium");
+ getParams.putSingle("search", "after:2010 before:2040-08 tag:super shared:yes lang:eng title description full:uranium");
response = documentResource.queryParams(getParams).get(ClientResponse.class);
json = response.getEntity(JSONObject.class);
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
@@ -216,6 +239,17 @@ public class TestDocumentResource extends BaseJerseyTest {
documents = json.getJSONArray("documents");
Assert.assertTrue(documents.length() == 0);
+ // Search documents (nothing)
+ documentResource = resource().path("/document/list");
+ documentResource.addFilter(new CookieAuthenticationFilter(document1Token));
+ getParams = new MultivaluedMapImpl();
+ getParams.putSingle("search", "full:random");
+ response = documentResource.queryParams(getParams).get(ClientResponse.class);
+ json = response.getEntity(JSONObject.class);
+ Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
+ documents = json.getJSONArray("documents");
+ Assert.assertTrue(documents.length() == 0);
+
// Search documents (nothing)
documentResource = resource().path("/document/list");
documentResource.addFilter(new CookieAuthenticationFilter(document1Token));