Skip to content

Commit

Permalink
Search within documents.
Browse files Browse the repository at this point in the history
  • Loading branch information
mkalus committed Aug 26, 2015
1 parent db2b666 commit 8cf0f9c
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 5 deletions.
14 changes: 14 additions & 0 deletions src/main/java/org/segrada/controller/SearchController.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,18 @@ public Viewable index(
}
return new Viewable("search/index", model);
}

@GET
@Path("/in_document")
@Produces(MediaType.TEXT_HTML)
public Viewable searchInDocument(
@QueryParam("s") String term,
@QueryParam("id") String id
) {
// create model map
Map<String, Object> model = new HashMap<>();
model.put("hits", searchEngine.searchInDocument(term, id));

return new Viewable("search/in_document", model);
}
}
8 changes: 8 additions & 0 deletions src/main/java/org/segrada/search/SearchEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ public interface SearchEngine {
*/
PaginationInfo<SearchHit> search(String searchTerm, Map<String, String> filters);

/**
* search within a document for certain terms and return list of highlighted hits
* @param searchTerm term(s) to search for
* @param id of document to search in
* @return list of highlighted hits or empty array
*/
String[] searchInDocument(String searchTerm, String id);

/**
* Remove entity from index
*
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/org/segrada/search/lucene/LuceneSearchEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,43 @@ else if (searchFilters.size() > 1) {
return new PaginationInfo<>(page, 1, 0, entriesPerPage, new LinkedList<>());
}

@Override
public String[] searchInDocument(String searchTerm, String id) {
// sanity check
if (searchTerm == null || id == null || searchTerm.isEmpty() || id.isEmpty()) return new String[]{};

try {
DirectoryReader iReader = DirectoryReader.open(directory);
IndexSearcher iSearcher = new IndexSearcher(iReader);

// only search content
MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_47, new String[]{"content"}, analyzer);

// set operator and contain by id
parser.setDefaultOperator(QueryParser.Operator.AND);
Query query = parser.parse(searchTerm);
Filter filter = new QueryWrapperFilter(new TermQuery(new Term("id", id)));

// do search, maximum of 1 document
TopDocs topDocs = iSearcher.search(query, filter, 1);

if (topDocs.scoreDocs.length > 0) {
ScoreDoc scoreDoc = topDocs.scoreDocs[0];

// get highlighted text
FastVectorHighlighter highlighter = new FastVectorHighlighter();
FieldQuery fieldQuery = highlighter.getFieldQuery(new QueryParser(Version.LUCENE_47, "content", analyzer).parse(searchTerm), iReader);

// return max of 100 highlighted elements
return highlighter.getBestFragments(fieldQuery, iReader, scoreDoc.doc, "content", 100, 100);
}
} catch (Throwable e) {
logger.error("Error in search.", e);
}

return new String[]{};
}

@Override
public synchronized void remove(String id) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.google.inject.Inject;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.flexible.standard.QueryParserUtil;
Expand Down
27 changes: 27 additions & 0 deletions src/main/resources/js/segrada.js
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,33 @@
}
});

// second type of data form (left side)
$("form.sg-simple-form", part).ajaxForm({
beforeSubmit: function (arr, $form, options) {
// disable form elements
$(":input", $form).attr("disabled", true);

// determine target to replace
var target = $form.attr('data-id');
if (typeof target !== 'undefined') target = $('#' + target);
target = target || $form;

target.html($('#sg-wait'));

return true;
},
success: function (responseText, statusText, xhr, $form) {
// determine target to replace
var target = $form.attr('data-id');
if (typeof target !== 'undefined') target = $('#' + target);
target = target || $form;

target.html(responseText);

$(":input", $form).attr("disabled", false);
}
});

// *******************************************************
// period handler
$('.sg-periods').each(function() {
Expand Down
7 changes: 7 additions & 0 deletions src/main/resources/less/single/segrada.less
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ a.sg-data-icon {
overflow: hidden;
}

.sg-highlight-list div {
margin-bottom: 0.1ex;
}
.sg-highlight-list div:hover {
background: #eee;
}

/* Settings for icons */
img.sg-img-pictogram {
width: 24px;
Expand Down
4 changes: 3 additions & 1 deletion src/main/webapp/WEB-INF/i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ error.calendar.fromTo=Start date must not be after end date.
error.calendar.incorrect=Date entry is not a correct date (try MM/DD/YYYY or MM/YYY or YYYY).
error.double=This field has to be unique.
error.entityNotFound=Entity not found!
error.nothingFound=Nothing found!
error.notEmpty=Value must not be empty
error.notNull=Value must not be empty
error.rangeLatCoordinate=Coordinate must be between -90 and 90.
Expand Down Expand Up @@ -162,4 +163,5 @@ Tags=Tags
Tag=Tag
Unlink=Delete connection
Users=Users
User=User
User=User
field.searchWithinDocument=Search within full text of document
4 changes: 3 additions & 1 deletion src/main/webapp/WEB-INF/i18n/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ error.calendar.fromTo=Startdatum darf nicht hinter Anfangsdatum liegen.
error.calendar.incorrect=Datumseintrag ist nicht korrekt (Format sollte TT.MM.YYYY, MM.YYYY oder YYYY sein).
error.double=Feldinhalt muss einzigartig sein.
error.entityNotFound=Datensatz wurde nicht gefunden!
error.nothingFound=Nichts gefunden!
error.notEmpty=Wert darf nicht leer sein.
error.notNull=Wert darf nicht leer sein.
error.rangeLatCoordinate=Koordinate muss zwischen -180 und 180 liegen.
Expand Down Expand Up @@ -162,4 +163,5 @@ Tags=Tags
Tag=Tag
Unlink=Verkn\u00FCpfung l\u00F6schen
User=Benutzer
Users=Benutzer
Users=Benutzer
field.searchWithinDocument=Innerhalb des Dokuments suchen
14 changes: 14 additions & 0 deletions src/main/webapp/WEB-INF/templates/file/show.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ <h4 class="sg-data-header">
</div>
</div>

<form class="sg-margin-top sg-simple-form" action="#" method="get" th:unless="${#strings.isEmpty(entity.fullText)}" th:action="@{/search/in_document}" th:attr="data-id=${'s-' + entity.uid + '-content'}">
<div class="form-group">
<label for="s" th:for="${'s-' + entity.uid}" th:text="#{field.searchWithinDocument}">Search within full text of document</label>
<input type="text" class="form-control" id="s" th:id="${'s-' + entity.uid}" name="s" />
</div>

<input type="hidden" name="id" th:value="${entity.uid}" />
<div class="sg-margin-top-sm">
<button type="submit" class="btn btn-default" th:text="#{Search}">Search</button>
</div>
</form>

<div id="s-x" th:id="${'s-' + entity.uid + '-content'}"></div>

<div th:if="${entity.fileIdentifier}" class="sg-margin-top sg-margin-bottom">
<div th:if="${#strings.startsWith(entity.mimeType,'image/')}">
<img src="#" th:src="@{/file/file/{uid}(uid=${entity.uid})}" alt="" th:alt-title="${entity.title}" style="width: 100%;" />
Expand Down
25 changes: 25 additions & 0 deletions src/main/webapp/WEB-INF/templates/search/in_document.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org" th:lang="${#locale.language}">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title th:text="#{Search}">Search</title>
<div th:include="partials/common :: head" th:remove="tag"></div>
</head>

<body>
<div th:replace="partials/common :: browser"></div>

<div class="container" th:fragment="content">
<div th:unless="${#arrays.isEmpty(hits)}" class="small sg-margin-top sg-margin-top sg-highlight-list">
<div th:each="highlightText : ${hits}" th:utext="${highlightText}"></div>
</div>
<div th:if="${#arrays.isEmpty(hits)}" class="small">
<div class="alert alert-danger sg-margin-top" role="alert" th:text="#{error.nothingFound}">
ERROR
</div>
</div>
</div>

</body>
</html>
2 changes: 1 addition & 1 deletion src/main/webapp/css/segrada.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8cf0f9c

Please sign in to comment.