From 12a2f9579104c01395200183b7f42ee1c4e034dc Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Thu, 28 Nov 2024 12:39:39 -0500 Subject: [PATCH] Connect FirstMatchHighlighter through to searchBar Co-authored-by: Sam Pillsworth --- .../main/scala/pink/cozydev/protosearch/Hit.scala | 1 + .../scala/pink/cozydev/protosearch/MultiIndex.scala | 13 +++++++++---- .../highlight/FirstMatchHighlighterSuite.scala | 2 +- .../scala/pink/cozydev/protosearch/JsInterop.scala | 3 ++- .../pink/cozydev/protosearch/sbt/search.js | 2 +- .../pink/cozydev/protosearch/sbt/searchBar.js | 2 +- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala/pink/cozydev/protosearch/Hit.scala b/core/src/main/scala/pink/cozydev/protosearch/Hit.scala index 34da1f10..0cfad5a3 100644 --- a/core/src/main/scala/pink/cozydev/protosearch/Hit.scala +++ b/core/src/main/scala/pink/cozydev/protosearch/Hit.scala @@ -26,4 +26,5 @@ case class Hit( val id: Int, val score: Double, val fields: Map[String, String], + val highlight: String, ) diff --git a/core/src/main/scala/pink/cozydev/protosearch/MultiIndex.scala b/core/src/main/scala/pink/cozydev/protosearch/MultiIndex.scala index fc97d4ac..ae3c2d3c 100644 --- a/core/src/main/scala/pink/cozydev/protosearch/MultiIndex.scala +++ b/core/src/main/scala/pink/cozydev/protosearch/MultiIndex.scala @@ -17,6 +17,7 @@ package pink.cozydev.protosearch import pink.cozydev.lucille.Query +import pink.cozydev.protosearch.highlight.{FirstMatchHighlighter, FragmentFormatter} case class MultiIndex( indexes: Map[String, Index], @@ -26,6 +27,7 @@ case class MultiIndex( private val indexSearcher = IndexSearcher(this, schema.defaultOR) private val scorer = Scorer(this, schema.defaultOR) + private val highlighter = FirstMatchHighlighter(FragmentFormatter(100, "", "")) val queryAnalyzer = schema.queryAnalyzer(schema.defaultField) /** Search the index with a `Query`. Results are sorted by descending score. @@ -33,11 +35,14 @@ case class MultiIndex( * @param q The `Query` to search * @return A list of `Hit`s or error */ - def search(q: Query): Either[String, List[Hit]] = { + def search(rawQStr: String, q: Query): Either[String, List[Hit]] = { val docs = indexSearcher.search(q).flatMap(ds => scorer.score(q, ds)) val lstb = List.newBuilder[Hit] docs.map(_.foreach { case (docId, score) => - lstb += Hit(docId, score, fields.map { case (k, v) => (k, v(docId)) }) + val docFields = fields.map { case (k, v) => (k, v(docId)) } + val highlight = + docFields.get("body").map(b => highlighter.highlight(b, rawQStr)).getOrElse("") + lstb += Hit(docId, score, docFields, highlight) }) docs.map(_ => lstb.result()) } @@ -48,7 +53,7 @@ case class MultiIndex( * @return A list of `Hit`s or error */ def search(q: String): Either[String, List[Hit]] = - queryAnalyzer.parse(q).flatMap(search) + queryAnalyzer.parse(q).flatMap(pq => search(q, pq)) /** Search the index with a possibly incomplete query. Meant for use in a "search as your type" * scenario. The last term, which is possibly incomplete, is rewritten to be a prefix. @@ -59,7 +64,7 @@ case class MultiIndex( def searchInteractive(partialQuery: String): Either[String, List[Hit]] = { val rewriteQ = queryAnalyzer.parse(partialQuery).map(mq => mq.mapLastTerm(LastTermRewrite.termToPrefix)) - rewriteQ.flatMap(search) + rewriteQ.flatMap(newq => search(partialQuery, newq)) } } object MultiIndex { diff --git a/core/src/test/scala/pink/cozydev/protosearch/highlight/FirstMatchHighlighterSuite.scala b/core/src/test/scala/pink/cozydev/protosearch/highlight/FirstMatchHighlighterSuite.scala index 936051c8..4bb7a798 100644 --- a/core/src/test/scala/pink/cozydev/protosearch/highlight/FirstMatchHighlighterSuite.scala +++ b/core/src/test/scala/pink/cozydev/protosearch/highlight/FirstMatchHighlighterSuite.scala @@ -17,7 +17,7 @@ package pink.cozydev.protosearch.highlight class FirstMatchHighlighterSuite extends munit.FunSuite { - val formatter = FragmentFormatter(36, "", "") + val formatter = FragmentFormatter(60, "", "") val highlighter = FirstMatchHighlighter(formatter) test("no highlight on no match") { diff --git a/jsinterop/src/main/scala/pink/cozydev/protosearch/JsInterop.scala b/jsinterop/src/main/scala/pink/cozydev/protosearch/JsInterop.scala index 582f1780..cc0f22fe 100644 --- a/jsinterop/src/main/scala/pink/cozydev/protosearch/JsInterop.scala +++ b/jsinterop/src/main/scala/pink/cozydev/protosearch/JsInterop.scala @@ -26,6 +26,7 @@ class JsHit( val id: Int, val score: Double, val fields: js.Dictionary[String], + val highlight: String, ) extends js.Object @JSExportTopLevel("Querier") @@ -40,7 +41,7 @@ class Querier(val mIndex: MultiIndex) { err => { println(err); Nil }, identity, ) - .map(h => new JsHit(h.id, h.score, h.fields.toJSDictionary)) + .map(h => new JsHit(h.id, h.score, h.fields.toJSDictionary, h.highlight)) hits.toJSArray } } diff --git a/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.js b/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.js index 21c5ff4b..d10b51b9 100644 --- a/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.js +++ b/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.js @@ -2,7 +2,7 @@ function renderDoc(hit) { const path = hit.fields.path const link = "../" + hit.fields.path.replace(".txt", ".html") const title = hit.fields.title - const preview = hit.fields.body.slice(0, 150) + "..." + const preview = hit.highlight return ( `
    diff --git a/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/searchBar.js b/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/searchBar.js index 2ef657e4..66a5c7e2 100644 --- a/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/searchBar.js +++ b/laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/searchBar.js @@ -3,7 +3,7 @@ function render(hit) { const htmlPath = hit.fields.path.replace(".txt", ".html") const link = new URL("../" + htmlPath, baseUrl) const title = hit.fields.title - const preview = hit.fields.body.slice(0, 150) + "..." + const preview = hit.highlight return ( `