diff --git a/peachjam/js/components/FindDocuments/SearchResult.vue b/peachjam/js/components/FindDocuments/SearchResult.vue index 760878434..c90f937d3 100644 --- a/peachjam/js/components/FindDocuments/SearchResult.vue +++ b/peachjam/js/components/FindDocuments/SearchResult.vue @@ -53,6 +53,15 @@ +
+ +
import JsonTable from './JsonTable.vue'; +import SearchResultProvision from './SearchResultProvision.vue'; export default { name: 'SearchResult', components: { - JsonTable + JsonTable, + SearchResultProvision }, props: { item: { @@ -125,6 +136,15 @@ export default { return Array.isArray(item.authors) ? ', '.join(item.authors) : item.authors; } return ''; + }, + provisionParents (provision) { + // zip item.parent_titles and item.parent_ids + return provision.parent_titles.map((title, index) => { + return { + title: title, + id: provision.parent_ids[index] + }; + }); } } }; diff --git a/peachjam/js/components/FindDocuments/SearchResultProvision.vue b/peachjam/js/components/FindDocuments/SearchResultProvision.vue new file mode 100644 index 000000000..752916161 --- /dev/null +++ b/peachjam/js/components/FindDocuments/SearchResultProvision.vue @@ -0,0 +1,27 @@ + + + diff --git a/peachjam_search/documents.py b/peachjam_search/documents.py index 521a60223..333b39820 100644 --- a/peachjam_search/documents.py +++ b/peachjam_search/documents.py @@ -105,7 +105,7 @@ class SearchableDocument(Document): pages = fields.NestedField( properties={ "page_num": fields.IntegerField(), - "body": fields.TextField(analyzer="standard", fields={"exact": Text()}), + "body": fields.TextField(fields={"exact": Text()}), } ) @@ -115,7 +115,7 @@ class SearchableDocument(Document): "id": fields.KeywordField(), "parent_titles": fields.TextField(), "parent_ids": fields.KeywordField(), - "body": fields.TextField(analyzer="standard", fields={"exact": Text()}), + "body": fields.TextField(fields={"exact": Text()}), } ) diff --git a/peachjam_search/serializers.py b/peachjam_search/serializers.py index 7ae2ba0d6..b76d2a5fe 100644 --- a/peachjam_search/serializers.py +++ b/peachjam_search/serializers.py @@ -8,6 +8,7 @@ class SearchableDocumentSerializer(DocumentSerializer): id = CharField(source="meta.id") highlight = SerializerMethodField() pages = SerializerMethodField() + provisions = SerializerMethodField() court = SerializerMethodField() nature = SerializerMethodField() order_outcome = SerializerMethodField() @@ -66,6 +67,20 @@ def get_pages(self, obj): pages.append(info) return pages + def get_provisions(self, obj): + """Serialize nested provision hits and highlights.""" + provisions = [] + if hasattr(obj.meta, "inner_hits"): + for provision in obj.meta.inner_hits.provisions.hits.hits: + info = provision._source.to_dict() + info["highlight"] = ( + provision.highlight.to_dict() + if hasattr(provision, "highlight") + else {} + ) + provisions.append(info) + return provisions + def get_court(self, obj): return obj["court" + self.language_suffix] diff --git a/peachjam_search/views.py b/peachjam_search/views.py index 12ee4cb2e..cb7db0b7c 100644 --- a/peachjam_search/views.py +++ b/peachjam_search/views.py @@ -61,6 +61,7 @@ def filter_queryset(self, request, queryset, view): should_queries.extend(self.build_basic_queries(request, view)) should_queries.extend(self.build_content_phrase_queries(request, view)) should_queries.extend(self.build_nested_page_queries(request, view)) + should_queries.extend(self.build_nested_provision_queries(request, view)) return queryset.query( "bool", @@ -159,6 +160,51 @@ def build_nested_page_queries(self, request, view): ) ] + def build_nested_provision_queries(self, request, view): + """Does a nested provision search, and includes highlights.""" + search_term = " ".join(self.get_search_query_params(request)) + if not search_term: + return [] + + return [ + Q( + "nested", + path="provisions", + query=Q( + "bool", + should=[ + MatchPhrase(provisions__body={"query": search_term, "slop": 2}), + SimpleQueryString( + query=search_term, + fields=["provisions.body"], + quote_field_suffix=".exact", + **view.simple_query_string_options, + ), + SimpleQueryString( + query=search_term, + fields=["provisions.title^4", "provisions.parent_titles^2"], + **view.simple_query_string_options, + ), + ], + ), + inner_hits={ + "_source": [ + "provisions.title", + "provisions.id", + "provisions.parent_titles", + "provisions.parent_ids", + ], + "highlight": { + "fields": {"provisions.body": {}}, + "pre_tags": [""], + "post_tags": [""], + "fragment_size": 80, + "number_of_fragments": 2, + }, + }, + ) + ] + class SearchView(TemplateView): template_name = "peachjam_search/search.html" @@ -304,7 +350,7 @@ class DocumentSearchViewSet(BaseDocumentViewSet): } # TODO perhaps better to explicitly include specific fields - source = {"excludes": ["pages", "content", "flynote", "case_summary"]} + source = {"excludes": ["pages", "content", "flynote", "case_summary", "provisions"]} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)