You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by pr...@apache.org on 2016/05/11 06:34:14 UTC
incubator-zeppelin git commit: [ZEPPELIN-599]notebook search should
search paragraph title
Repository: incubator-zeppelin
Updated Branches:
refs/heads/master 81b47c039 -> a87d45ec0
[ZEPPELIN-599]notebook search should search paragraph title
### What is this PR for?
Allow notebook search to search paragraph title too.
### What type of PR is it?
[Bug Fix]
### Todos
### What is the Jira issue?
[ZEPPELIN-599](https://issues.apache.org/jira/browse/ZEPPELIN-599?jql=project%20%3D%20ZEPPELIN%20AND%20status%20%3D%20Open%20AND%20text%20~%20%22Title%22)
### How should this be tested?
You should be able to search the the note by searching queryterm in the paragraph title.
### Screenshots (if appropriate)
Before:
![screen shot 2016-04-27 at 10 33 29 pm](https://cloud.githubusercontent.com/assets/7026661/14860836/39c9e870-0cc8-11e6-98ca-e4509aa97cf8.png)
After:
![screen shot 2016-04-27 at 10 24 14 pm](https://cloud.githubusercontent.com/assets/7026661/14860651/76c33e58-0cc7-11e6-8e72-2eb68e552168.png)
### Questions:
* Does the licenses files need update?NO
* Is there breaking changes for older versions?NO
* Does this needs documentation?NO
Author: Ravi Ranjan <ra...@gmail.com>
Closes #859 from ravicodder/searchTitle and squashes the following commits:
59b5a76 [Ravi Ranjan] Make code consistent
c8a9eaf [Ravi Ranjan] Merge branch 'master' of https://github.com/apache/incubator-zeppelin into searchTitle
cbded8d [Ravi Ranjan] Add test in LuceneSearchTest.java
b3e66bb [Ravi Ranjan] Add test
f6d64fd [Ravi Ranjan] Fix spacing
5830c8f [Ravi Ranjan] revert indent
ed69177 [Ravi Ranjan] Search Title of notebook
Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/a87d45ec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/a87d45ec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/a87d45ec
Branch: refs/heads/master
Commit: a87d45ec0460c64d709f8bc67e847bf17dc8f9d3
Parents: 81b47c0
Author: Ravi Ranjan <ra...@gmail.com>
Authored: Thu May 5 10:53:15 2016 +0530
Committer: Prabhjyot Singh <pr...@gmail.com>
Committed: Wed May 11 12:04:06 2016 +0530
----------------------------------------------------------------------
.../zeppelin/rest/ZeppelinRestApiTest.java | 26 ++++++++
.../src/app/search/result-list.controller.js | 36 ++++++++--
zeppelin-web/src/app/search/search.css | 5 ++
.../apache/zeppelin/search/LuceneSearch.java | 52 ++++++++++-----
.../zeppelin/search/LuceneSearchTest.java | 69 +++++++++++++++-----
5 files changed, 149 insertions(+), 39 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/a87d45ec/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
index 2f2a36b..36c95af 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
@@ -756,5 +756,31 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
ZeppelinServer.notebook.removeNote(note2.getId());
}
+ @Test
+ public void testTitleSearch() throws IOException {
+ Note note = ZeppelinServer.notebook.createNote();
+ String jsonRequest = "{\"title\": \"testTitleSearchOfParagraph\", \"text\": \"ThisIsToTestSearchMethodWithTitle \"}";
+ PostMethod postNotebookText = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest);
+ postNotebookText.releaseConnection();
+
+ GetMethod searchNotebook = httpGet("/notebook/search?q='testTitleSearchOfParagraph'");
+ searchNotebook.addRequestHeader("Origin", "http://localhost");
+ Map<String, Object> respSearchResult = gson.fromJson(searchNotebook.getResponseBodyAsString(),
+ new TypeToken<Map<String, Object>>() {
+ }.getType());
+ ArrayList searchBody = (ArrayList) respSearchResult.get("body");
+
+ int numberOfTitleHits = 0;
+ for (int i = 0; i < searchBody.size(); i++) {
+ Map<String, String> searchResult = (Map<String, String>) searchBody.get(i);
+ if (searchResult.get("header").contains("testTitleSearchOfParagraph")) {
+ numberOfTitleHits++;
+ }
+ }
+ assertEquals("Paragraph title hits must be at-least one", true, numberOfTitleHits >= 1);
+ searchNotebook.releaseConnection();
+ ZeppelinServer.notebook.removeNote(note.getId());
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/a87d45ec/zeppelin-web/src/app/search/result-list.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/search/result-list.controller.js b/zeppelin-web/src/app/search/result-list.controller.js
index 0d55442..949e01f 100644
--- a/zeppelin-web/src/app/search/result-list.controller.js
+++ b/zeppelin-web/src/app/search/result-list.controller.js
@@ -74,12 +74,20 @@ angular
};
}
- var lines = note.snippet
+ var result = '';
+ if (note.header !== '') {
+ result = note.header + '\n\n' + note.snippet;
+ } else {
+ result = note.snippet;
+ }
+
+ var lines = result
.split('\n')
.map(function(line, row) {
+
var match = line.match(/<B>(.+?)<\/B>/);
- // return early if nothing to highlight
+ // return early if nothing to highlight
if (!match) {
return line;
}
@@ -93,15 +101,31 @@ angular
indeces.forEach(function(start) {
var end = start + term.length;
- _editor
- .getSession()
- .addMarker(
+ if (note.header !== '' && row === 0) {
+ _editor
+ .getSession()
+ .addMarker(
+ new Range(row, 0, row, line.length),
+ 'search-results-highlight-header',
+ 'background'
+ );
+ _editor
+ .getSession()
+ .addMarker(
new Range(row, start, row, end),
'search-results-highlight',
'line'
);
+ } else {
+ _editor
+ .getSession()
+ .addMarker(
+ new Range(row, start, row, end),
+ 'search-results-highlight',
+ 'line'
+ );
+ }
});
-
return __line;
});
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/a87d45ec/zeppelin-web/src/app/search/search.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/search/search.css b/zeppelin-web/src/app/search/search.css
index e89c765..b06b4a9 100644
--- a/zeppelin-web/src/app/search/search.css
+++ b/zeppelin-web/src/app/search/search.css
@@ -31,6 +31,11 @@
position: absolute;
}
+.search-results-highlight-header {
+ background-color: #e6f2ff;
+ position: absolute;
+}
+
/* remove error highlighting */
.search-results .ace_invalid {
background: none !important;
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/a87d45ec/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
index 7f9cbbd..b43c453 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
@@ -37,6 +37,7 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
+import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
@@ -69,7 +70,8 @@ import com.google.common.collect.Lists;
public class LuceneSearch implements SearchService {
private static final Logger LOG = LoggerFactory.getLogger(LuceneSearch.class);
- private static final String SEARCH_FIELD = "contents";
+ private static final String SEARCH_FIELD_TEXT = "contents";
+ private static final String SEARCH_FIELD_TITLE = "header";
static final String PARAGRAPH = "paragraph";
static final String ID_FIELD = "id";
@@ -85,7 +87,7 @@ public class LuceneSearch implements SearchService {
try {
writer = new IndexWriter(ramDirectory, iwc);
} catch (IOException e) {
- LOG.error("Failed to reate new IndexWriter", e);
+ LOG.error("Failed to create new IndexWriter", e);
}
}
@@ -102,10 +104,12 @@ public class LuceneSearch implements SearchService {
try (IndexReader indexReader = DirectoryReader.open(ramDirectory)) {
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
Analyzer analyzer = new StandardAnalyzer();
- QueryParser parser = new QueryParser(SEARCH_FIELD, analyzer);
+ MultiFieldQueryParser parser = new MultiFieldQueryParser(
+ new String[] {SEARCH_FIELD_TEXT, SEARCH_FIELD_TITLE},
+ analyzer);
Query query = parser.parse(queryStr);
- LOG.debug("Searching for: " + query.toString(SEARCH_FIELD));
+ LOG.debug("Searching for: " + query.toString(SEARCH_FIELD_TEXT));
SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter();
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
@@ -139,20 +143,33 @@ public class LuceneSearch implements SearchService {
LOG.debug(" Title: {}", doc.get("title"));
}
- String text = doc.get(SEARCH_FIELD);
- TokenStream tokenStream = TokenSources.getTokenStream(searcher.getIndexReader(), id,
- SEARCH_FIELD, analyzer);
- TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, text, true, 3);
- LOG.debug(" {} fragments found for query '{}'", frag.length, query);
- for (int j = 0; j < frag.length; j++) {
- if ((frag[j] != null) && (frag[j].getScore() > 0)) {
- LOG.debug(" Fragment: {}", frag[j].toString());
+ String text = doc.get(SEARCH_FIELD_TEXT);
+ String header = doc.get(SEARCH_FIELD_TITLE);
+ String fragment = "";
+
+ if (text != null) {
+ TokenStream tokenStream = TokenSources.getTokenStream(searcher.getIndexReader(), id,
+ SEARCH_FIELD_TEXT, analyzer);
+ TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, text, true, 3);
+ LOG.debug(" {} fragments found for query '{}'", frag.length, query);
+ for (int j = 0; j < frag.length; j++) {
+ if ((frag[j] != null) && (frag[j].getScore() > 0)) {
+ LOG.debug(" Fragment: {}", frag[j].toString());
+ }
}
+ fragment = (frag != null && frag.length > 0) ? frag[0].toString() : "";
}
- String fragment = (frag != null && frag.length > 0) ? frag[0].toString() : "";
+ if (header != null) {
+ TokenStream tokenTitle = TokenSources.getTokenStream(searcher.getIndexReader(), id,
+ SEARCH_FIELD_TITLE, analyzer);
+ TextFragment[] frgTitle = highlighter.getBestTextFragments(tokenTitle, header, true, 3);
+ header = (frgTitle != null && frgTitle.length > 0) ? frgTitle[0].toString() : "";
+ } else {
+ header = "";
+ }
matchingParagraphs.add(ImmutableMap.of("id", path, // <noteId>/paragraph/<paragraphId>
- "name", title, "snippet", fragment, "text", text));
+ "name", title, "snippet", fragment, "text", text, "header", header));
} else {
LOG.info("{}. No {} for this document", i + 1, ID_FIELD);
}
@@ -252,11 +269,14 @@ public class LuceneSearch implements SearchService {
doc.add(new StringField("title", noteName, Field.Store.YES));
if (null != p) {
- doc.add(new TextField(SEARCH_FIELD, p.getText(), Field.Store.YES));
+ doc.add(new TextField(SEARCH_FIELD_TEXT, p.getText(), Field.Store.YES));
+ if (p.getTitle() != null) {
+ doc.add(new TextField(SEARCH_FIELD_TITLE, p.getTitle(), Field.Store.YES));
+ }
Date date = p.getDateStarted() != null ? p.getDateStarted() : p.getDateCreated();
doc.add(new LongField("modified", date.getTime(), Field.Store.NO));
} else {
- doc.add(new TextField(SEARCH_FIELD, noteName, Field.Store.YES));
+ doc.add(new TextField(SEARCH_FIELD_TEXT, noteName, Field.Store.YES));
}
return doc;
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/a87d45ec/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
index f74d95e..c744267 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
@@ -65,8 +65,8 @@ public class LuceneSearchTest {
@Test public void canIndexNotebook() {
//give
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraph("Notebook2", "not test");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraph("Notebook2", "not test");
List<Note> notebook = Arrays.asList(note1, note2);
//when
@@ -75,8 +75,8 @@ public class LuceneSearchTest {
@Test public void canIndexAndQuery() {
//given
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
//when
@@ -91,8 +91,8 @@ public class LuceneSearchTest {
@Test public void canIndexAndQueryByNotebookName() {
//given
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
//when
@@ -104,9 +104,31 @@ public class LuceneSearchTest {
assertThat(results.get(0)).containsEntry("id", note1.getId());
}
+ @Test
+ public void canIndexAndQueryByParagraphTitle() {
+ //given
+ Note note1 = newNoteWithParagraph("Notebook1", "test", "testingTitleSearch");
+ Note note2 = newNoteWithParagraph("Notebook2", "not test", "notTestingTitleSearch");
+ notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
+
+ //when
+ List<Map<String, String>> results = notebookIndex.query("testingTitleSearch");
+
+ //then
+ assertThat(results).isNotEmpty();
+ assertThat(results.size()).isAtLeast(1);
+ int TitleHits = 0;
+ for (Map<String, String> res : results) {
+ if (res.get("header").contains("testingTitleSearch")) {
+ TitleHits++;
+ }
+ }
+ assertThat(TitleHits).isAtLeast(1);
+ }
+
@Test public void indexKeyContract() throws IOException {
//give
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
//when
notebookIndex.addIndexDoc(note1);
//then
@@ -129,8 +151,8 @@ public class LuceneSearchTest {
@Test public void canIndexAndReIndex() throws IOException {
//given
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
//when
@@ -155,8 +177,8 @@ public class LuceneSearchTest {
@Test public void canDeleteFromIndex() throws IOException {
//given
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
assertThat(resultForQuery("Notebook2")).isNotEmpty();
@@ -174,8 +196,8 @@ public class LuceneSearchTest {
@Test public void indexParagraphUpdatedOnNoteSave() throws IOException {
//given: total 2 notebooks, 3 paragraphs
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
assertThat(resultForQuery("test").size()).isEqualTo(3);
@@ -199,8 +221,8 @@ public class LuceneSearchTest {
@Test public void indexNoteNameUpdatedOnNoteSave() throws IOException {
//given: total 2 notebooks, 3 paragraphs
- Note note1 = newNoteWithParapgraph("Notebook1", "test");
- Note note2 = newNoteWithParapgraphs("Notebook2", "not test", "not test at all");
+ Note note1 = newNoteWithParagraph("Notebook1", "test");
+ Note note2 = newNoteWithParagraphs("Notebook2", "not test", "not test at all");
notebookIndex.addIndexDocs(Arrays.asList(note1, note2));
assertThat(resultForQuery("test").size()).isEqualTo(3);
@@ -226,17 +248,23 @@ public class LuceneSearchTest {
* @param parText text of the paragraph
* @return Note
*/
- private Note newNoteWithParapgraph(String noteName, String parText) {
+ private Note newNoteWithParagraph(String noteName, String parText) {
Note note1 = newNote(noteName);
addParagraphWithText(note1, parText);
return note1;
}
+ private Note newNoteWithParagraph(String noteName, String parText,String title) {
+ Note note = newNote(noteName);
+ addParagraphWithTextAndTitle(note, parText, title);
+ return note;
+ }
+
/**
* Creates a new Note \w given name,
* adds N paragraphs \w given texts
*/
- private Note newNoteWithParapgraphs(String noteName, String... parTexts) {
+ private Note newNoteWithParagraphs(String noteName, String... parTexts) {
Note note1 = newNote(noteName);
for (String parText : parTexts) {
addParagraphWithText(note1, parText);
@@ -250,6 +278,13 @@ public class LuceneSearchTest {
return p;
}
+ private Paragraph addParagraphWithTextAndTitle(Note note, String text, String title) {
+ Paragraph p = note.addParagraph();
+ p.setText(text);
+ p.setTitle(title);
+ return p;
+ }
+
private Note newNote(String name) {
Note note = new Note(notebookRepoMock, replLoaderMock, null, notebookIndex);
note.setName(name);