Replaced plain_text with search_text, a list of blocks with keys, and wired search UI to link to document key, allowing for linking to a search result's place in the text.

This commit is contained in:
Alex Hunt 2018-05-20 13:42:51 -04:00
parent 3c5b93b3c2
commit 1d862cd30f
11 changed files with 174 additions and 413 deletions

View File

@ -19,7 +19,7 @@ def es_document_list(doc_type):
search = es.search(
index='joyce',
doc_type=doc_type,
_source_exclude=['html_source', 'plain_text'],
_source_exclude=['html_source', 'search_text'],
body={
'from': 0, 'size': 10000,
'query': {'match_all': {}},
@ -93,32 +93,60 @@ def group_search_results(es_results):
for result in es_results:
types.add(result['_type'])
for type in types:
list = []
documents = []
for result in es_results:
if result['_type'] == type:
entry = {'id': result['_id'], 'title': result['_source']['title'], 'highlight': result['highlight']['plain_text']}
list.append(entry)
output_results[type] = list
hits = []
for hit in result['inner_hits']['search_text']['hits']['hits']:
hits.append(hit['_source'])
entry = {
'id': result['_id'],
'title': result['_source']['title'],
'hits': hits
}
if type == 'chapter':
entry['number'] = result['_source']['number']
documents.append(entry)
output_results[type] = documents
return output_results
def es_search_text(body):
search = es.search(
index='joyce',
filter_path=['hits.hits._id', 'hits.hits._type', 'hits.hits._source.title', 'hits.hits._source.number', 'hits.hits.highlight', 'hits.hits.title'],
filter_path=[
'hits.hits._id',
'hits.hits._type',
'hits.hits._source.title',
'hits.hits._source.number',
'hits.hits.title',
'hits.hits.inner_hits.search_text.hits.hits._source'
],
body={
'from': 0,
'size': 10,
'query': {
'match': {
'plain_text': {
'query': body
"nested": {
"path": "search_text",
"query": {
"bool": {
"must": [
{ "match": { "search_text.text": body}}
]
}
},
"inner_hits": {
"highlight": {
"fields": {
"search_text.text": {}
}
}
}
}
}
},
'highlight' : {
'number_of_fragments' : 15,
'fields' : {
'plain_text': {
'search_text': {
'matched_fields': 'text',
'type': 'unified',
'pre_tags' : [''],

96
dist/js/editor.js vendored

File diff suppressed because one or more lines are too long

96
dist/js/joyce.js vendored Normal file

File diff suppressed because one or more lines are too long

96
dist/js/notes.js vendored

File diff suppressed because one or more lines are too long

96
dist/js/reader.js vendored

File diff suppressed because one or more lines are too long

96
dist/js/search.js vendored

File diff suppressed because one or more lines are too long

View File

@ -43,21 +43,21 @@ create_index_settings = {
'number': {'type': 'integer'},
'title': {'type': 'keyword'},
'html_source': {'type': 'text', 'analyzer': 'html_analyzer'},
'plain_text': {'type': 'text'}
'search_text': {'type': 'nested'}
}
},
'note': {
'properties': {
'title': {'type': 'keyword'},
'html_source': {'type': 'text', 'analyzer': 'html_analyzer'},
'plain_text': {'type': 'text'}
'search_text': {'type': 'nested'}
}
},
'note': {
'tag': {
'properties': {
'title': {'type': 'keyword'},
'html_source': {'type': 'text', 'analyzer': 'html_analyzer'},
'plain_text': {'type': 'text'}
'search_text': {'type': 'nested'}
}
}
}

View File

@ -1,13 +1,24 @@
import React from 'react'
import PropTypes from 'prop-types'
const SearchResultSnippet = ({snippet}) =>
<div>
{snippet}...
const buildSnippetLink = (key, docType, route) => {
console.log('DocType is ', docType)
if (docType === 'chapter') {
return '/' + route + '#' + key
} else {
return '/' + docType + 's/' + route + '#' + key
}
}
const SearchResultSnippet = ({snippet, docType, route}) =>
<div id={snippet.key}>
<a href={buildSnippetLink(snippet.key, docType, route)}>
{snippet.text}
</a>
</div>
SearchResultSnippet.propTypes = {
snippet: PropTypes.string,
snippet: PropTypes.object,
}
export default SearchResultSnippet

View File

@ -9,8 +9,8 @@ const SearchResultGroup = ({docType, docTitle, results}) =>
{results.map(result =>
<div key={result.id}>
<h5>{result.title}</h5>
{result.highlight.map(highlight =>
<SearchResultSnippet snippet={highlight} />
{result.hits.map(hit =>
<SearchResultSnippet key={hit.key} snippet={hit} docType={docType} route={docType === 'chapter' ? result.number : result.id}/>
)}
</div>
)}

View File

@ -4,7 +4,7 @@ import { stateToHTML } from 'draft-js-export-html'
import actions from '../actions'
import helpers from '../modules/helpers'
import { html_export_options, convertToPlainText } from '../modules/editorSettings.js'
import { html_export_options, convertToSearchText } from '../modules/editorSettings.js'
const joyceInterface = store => next => action => {
next(action)
@ -14,7 +14,7 @@ const joyceInterface = store => next => action => {
break
case 'SUBMIT_DOCUMENT_EDIT':
const textContent = action.editorState.getCurrentContent()
const data = { title: action.documentTitleInput, html_source: stateToHTML(textContent, html_export_options), plain_text: convertToPlainText(textContent) }
const data = { title: action.documentTitleInput, html_source: stateToHTML(textContent, html_export_options), search_text: convertToSearchText(textContent) }
if (action.currentDocument.id) {
data.id = action.currentDocument.id
}

View File

@ -1,6 +1,14 @@
import { convertToRaw } from 'draft-js'
export const html_export_options = {
blockStyleFn: (block) => {
const key = block.getKey()
return {
attributes: {
id: key
}
}
},
entityStyleFn: (entity) => {
const entityType = entity.get('type').toUpperCase()
if (entityType === 'LINK') {
@ -8,7 +16,7 @@ export const html_export_options = {
return {
element: 'a',
attributes: {
'href': data.url,
'href': data.url,
'data-target': '#annotation_modal',
'data-toggle': 'modal'
}
@ -17,10 +25,12 @@ export const html_export_options = {
}
}
export const convertToPlainText = contentState => {
export const convertToSearchText = contentState => {
const rawState = convertToRaw(contentState)
return rawState.blocks.reduce(
(plaintText, block) => plaintText + block.text + '\n',
''
)
const searchText = rawState.blocks.reduce(
(searchText, block) => ([...searchText, {key: block.key, text: block.text}]),
[]
)
console.log('Search text result:', searchText)
return searchText
}