diff --git a/src/jsMain/kotlin/examples/quotesearch/quotesearch.kt b/src/jsMain/kotlin/examples/quotesearch/quotesearch.kt index 30c9831..f738841 100644 --- a/src/jsMain/kotlin/examples/quotesearch/quotesearch.kt +++ b/src/jsMain/kotlin/examples/quotesearch/quotesearch.kt @@ -7,26 +7,28 @@ import com.jilesvangurp.rankquest.core.pluginconfiguration.Metric import com.jilesvangurp.rankquest.core.pluginconfiguration.MetricConfiguration import com.jilesvangurp.rankquest.core.pluginconfiguration.SearchContextField import com.jilesvangurp.rankquest.core.pluginconfiguration.SearchPluginConfiguration +import com.jilesvangurp.rankquest.core.plugins.BuiltinPlugins +import com.jilesvangurp.rankquest.core.plugins.ElasticsearchPluginConfiguration import com.jilesvangurp.rankquest.core.plugins.PluginFactory import com.jilesvangurp.rankquest.core.plugins.PluginFactoryRegistry +import com.jillesvangurp.ktsearch.KtorRestClient import com.jillesvangurp.ktsearch.SearchClient import com.jillesvangurp.ktsearch.deleteIndex import com.jillesvangurp.ktsearch.index import com.jillesvangurp.ktsearch.repository.repository -import components.busyResult import components.confirm import components.runWithBusy import dev.fritz2.core.RootStore import dev.fritz2.remote.http -import handlerScope -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch +import koin import kotlinx.serialization.EncodeDefault import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable +import kotlinx.serialization.json.decodeFromJsonElement import org.koin.core.module.dsl.singleOf import org.koin.dsl.module import search.* +import searchpluginconfig.ActiveSearchPluginConfigurationStore import kotlin.math.min import kotlin.time.Duration.Companion.milliseconds @@ -141,6 +143,21 @@ fun List.searchPlugin(nice: Boolean = true): SearchPlugin { } class MovieQuotesStore : RootStore>(listOf()) { + val activeSearchPluginConfigurationStore = koin.get() + + fun searchClient(): SearchClient { + val config = activeSearchPluginConfigurationStore.current + return if (config != null && config.pluginType == BuiltinPlugins.ElasticSearch.name) { + config.pluginSettings?.let { + val esConfig = DEFAULT_JSON.decodeFromJsonElement(it) + val ktc = KtorRestClient(esConfig.host, esConfig.port, esConfig.https, esConfig.user, esConfig.password) + SearchClient(ktc) + } + } else { + null + } ?: SearchClient() + } + val load = handle { _, path -> http(path).get().body().let> { body -> DEFAULT_JSON.decodeFromString(body) @@ -151,7 +168,7 @@ class MovieQuotesStore : RootStore>(listOf()) { } val delRecipesES = handle { runWithBusy({ - val client = SearchClient() + val client = searchClient() client.deleteIndex("moviequotes") }) it @@ -164,14 +181,14 @@ class MovieQuotesStore : RootStore>(listOf()) { ) { runWithBusy({ - val client = SearchClient() // localhost:9200 is default + val client = searchClient() val repository = client.repository( "moviequotes", MovieQuote.serializer() ) repository.bulk(bulkSize = 500) { current.forEach { m -> - index(m, id=m.id) + index(m, id = m.id) } } }) diff --git a/src/jsMain/kotlin/searchpluginconfig/ActiveSearchPluginConfigurationStore.kt b/src/jsMain/kotlin/searchpluginconfig/ActiveSearchPluginConfigurationStore.kt index 5392184..a5c29e2 100644 --- a/src/jsMain/kotlin/searchpluginconfig/ActiveSearchPluginConfigurationStore.kt +++ b/src/jsMain/kotlin/searchpluginconfig/ActiveSearchPluginConfigurationStore.kt @@ -29,7 +29,6 @@ class ActiveSearchPluginConfigurationStore : LocalStoringStore> { config, query -> busyResult({ - val outcome = if (config != null) { val selectedPlugin = current if (selectedPlugin != null) { diff --git a/src/jsMain/kotlin/searchpluginconfig/searchpluginconfig.kt b/src/jsMain/kotlin/searchpluginconfig/searchpluginconfig.kt index 47e1c88..5645cdd 100644 --- a/src/jsMain/kotlin/searchpluginconfig/searchpluginconfig.kt +++ b/src/jsMain/kotlin/searchpluginconfig/searchpluginconfig.kt @@ -237,6 +237,8 @@ private fun RenderContext.help() { You should keep your configurations in a safe place. It is good practice to keep them in a git repository together with your test cases. + You also need to do this if you want to use [rankquest-cli](https://github.com/jillesvangurp/rankquest-cli). + ## Writing your own plugins Writing your own plugins is possible of course. However, this will require modifying some source code. diff --git a/src/jsMain/kotlin/testcases/testcases.kt b/src/jsMain/kotlin/testcases/testcases.kt index b00be99..ca8d70b 100644 --- a/src/jsMain/kotlin/testcases/testcases.kt +++ b/src/jsMain/kotlin/testcases/testcases.kt @@ -151,7 +151,8 @@ fun RenderContext.testCases() { infoPopup( "Creating Test Cases", """ This screen allows you to review and modify your test cases. When you create a test case - from the search screen, the results simply get rated in descending order. You can use this + from the search screen. Simply do a search and then click the "Add Testcase" button. + The results simply get rated in descending order. You can then use this screen to change the ratings. ## Demo content @@ -175,13 +176,13 @@ fun RenderContext.testCases() { A rating of zero means the document is not relevant. Higher ratings indicate a higher relevance. - ## Adding results to a test case + ## Adding more results to a test case - If you do a search in the search tool and then switch back to the test cases screen, + If you do another search in the search tool and then switch back to the test cases screen, you can add results from the search screen to any test case. This is a nice way to add documents that you know should be produced that the current search does not produce. - A second way to add results to test cases is from the metrics screen. When you review + Another way to add results to test cases is from the metrics screen. When you review the metrics, the the details for each test case will list any unrated results and give you the opportunity to add those to the test case. @@ -190,6 +191,8 @@ fun RenderContext.testCases() { You can download your test cases as a json file and later re-import them. You should use this feature to store your ratings in a safe place. A good practice is to keep them in a git repository. You can create specialized ratings files for different use cases, topics, etc. + + You also need to do this if you want to use [rankquest-cli](https://github.com/jillesvangurp/rankquest-cli). """.trimIndent() ) } diff --git a/src/jsMain/resources/about.md b/src/jsMain/resources/about.md index cf0f92a..035956a 100644 --- a/src/jsMain/resources/about.md +++ b/src/jsMain/resources/about.md @@ -23,8 +23,10 @@ You can also produce metrics from your builds by using the **command line** vers ## Links - [rankquest-studio](https://github.com/jillesvangurp/rankquest-studio) The github project for this web application. It's all written in kotlin-js and uses the wonderful [Fritz2](https://www.fritz2.dev/) framework. +- [rankquest-cli](https://github.com/jillesvangurp/rankquest-cli) A command line tool that you can use to use exported search configurations and test cases to run metrics from the command line or in your CI build. - [rankquest-core](https://github.com/jillesvangurp/rankquest-core) A Kotlin multiplatform kotlin library that implements the metrics and search plugins used in Rankquest Studio. -- [ktsearch](https://github.com/jillesvangurp/kt-search) A kotlin multiplatform library for using Elasticsearch and Opensearch. +- [ktsearch](https://github.com/jillesvangurp/kt-search) A kotlin multiplatform library for using Elasticsearch and Opensearch. This library is used to implement the Elasticsearch searchplugin and also used for the movie quotes demo. +- [querylight](https://github.com/jillesvangurp/querylight) An in memory search library that is used for the movie quotes demos. ## Why another tool? @@ -44,15 +46,15 @@ or Elasticsearch. You use these tools to test specific queries. While this is of this amounts to a form of whitebox testing where you make various assumptions about the internals of your product. In my view, search quality testing should be a blackbox test that runs directly against your API without making any assumptions about what -it uses internally. This allows you to radically change your implementation and compare +it uses internally or how it is implemented. This allows you to radically change your implementation and compare the before and after metrics. -Rankquest studio aims to address all these issues by providing a responsive and very usable UI +Rankquest studio aims to address all these issues by providing a simple but usable UI that allows people to simply get started by simply opening the app. There is **no installation -process**. Rankquest Studio is a web application. +process**. Rankquest Studio is a web site that you open and use. There is no server either (other than the simple web server that hosts the application). -It does not require a server or a database. Everything happens +It does not require an application server or a database. Everything happens in the browser. All the data it manipulates is stored in the browser. You can easily import and export ratings, configurations, and metrics reports in json format. The only network traffic that rank quest studio makes is to your own search service. @@ -60,23 +62,23 @@ traffic that rank quest studio makes is to your own search service. It makes no assumptions about how your search API works. It uses an extensible plugin model to talk to your search service. The only assumption it makes is that whatever you have can return a list of results with ids for a given search context (your search parameters). -## Support & Getting help with improving your ranking further +## Support & Getting help taking your search to the next level -Please provide feedback via the [Github Issue Tracker](https://github.com/jillesvangurp/rankquest-studio/issues) +Please provide feedback via the [Github Issue Tracker](https://github.com/jillesvangurp/rankquest-studio/issues). -This tool was created by me to help me evaluate our search quality in a few of my own projects and after years of observing my clients mostly ignoring search quality. With some notable exceptions, most companies don't employ search relevance experts, and have no good way to benchmark their search quality beyond manual testing. +I created Rankquest to help me evaluate our search quality in a few of my own projects and after years of observing my clients mostly ignoring search quality. With some notable exceptions, most companies don't employ search relevance experts, and have no good way to benchmark their search quality beyond manual testing. After looking at existing tools, I chose the more difficult but satisfying path of building yet another tool to address some of their limitations. I've been working with search technology for over twenty years and with Elasticsearch and Opensearch -for the last decade. I've worked with small and big companies in various roles and still do +for the last decade. I've worked with small and big companies in various roles and still occasionally do some consulting next to my main job as CTO of [FORMATION Gmbh](https://tryformation.com). -If you need help with your search, want an outside opinion about your current setup, or are struggling with your search quality, **I might be able to help you**. +If you need help with your search, want an outside opinion about your current setup, or are struggling with your search quality, **I might be able to help you**. And if not, I can connect you with people that can. -As a **search consultant**, I have advised many clients over the years on how to architect and use search effectively. This usually involves both advising on query and mapping strategies, refining their product strategy, coming up with good ETL strategies, coming up with solutions for difficult problems, and educating people about all this. Unfortunately, I am not able to join your team for extended amounts of time. However, I can add a lot of value quickly and help set your team up for success. My preferred way of working is doing short, result driven products and coaching people how to do what they need to get done. +As a **search consultant**, I have advised many clients over the years on how to architect and use search effectively. This usually involves both advising on query and mapping strategies, refining their product strategy, coming up with good ETL strategies, coming up with solutions for ranking challenges, and educating people about all this. Unfortunately, my main job as a CTO prevents me from joining your team for extended periods of time or on a full time basis. However, I can add a lot of value quickly and help set your company up for success. My preferred way of working is doing short, result driven products and coaching people how to do what they need to get done. The ideal outcome of a project for me is a happy customer that no longer needs my services because they are fully equipped to take the next steps. ## Showing your appreciation -This project is free and open source. If you like it, let me know & give me some feedback, tell others, star the project on [Github](https://github.com/jillesvangurp/rankquest-studio), etc. +This project is free and open source. If you like it, let me know & give me some feedback, tell others, star the project on [Github](https://github.com/jillesvangurp/rankquest-studio), etc. And consider engaging my services as a search consultant. ## Jilles van Gurp diff --git a/src/jsMain/resources/demo.md b/src/jsMain/resources/demo.md index e7ed408..8820771 100644 --- a/src/jsMain/resources/demo.md +++ b/src/jsMain/resources/demo.md @@ -9,11 +9,10 @@ test configurations to explore the Rankquest Studio UI. For this we use a small data set of 732 quotes from famous movies and three different configurations that allow you to explore this: -- Movie quotes search: uses the querylight library with a simple tf/idf index. +- Movie quotes search: uses the [querylight](https://github.com/jillesvangurp/querylight) library with a simple tf/idf index. - Movie quotes with ngrams: similar but it uses ngrams instead of terms. The metrics for this are a bit less iteresting. -- ES based movie search. Relies on an external elasticsearch that you have -to run locally +- ES based movie search. Relies on an external elasticsearch. ## Loading the test case @@ -26,16 +25,16 @@ explore some metrics. ## Using Elasticsearch -The ES based movie search of course requires elasticsearch. Two buttons are provided, -that create the index and remove it again. - -Unlike the two querylight demos, the elasticsearch one uses a plugin configuration that you can modify and tweak. +The ES based movie search of course requires elasticsearch. Unlike the two querylight demos, the elasticsearch demo uses a plugin configuration that you can modify and tweak. This is great for getting started! -Make sure elasticsearch is running on localhost and port 9200. If you use docker, -you can use this [docker-compose](docker-compose.yml) file to start elasticsearch -and kibana by downloading it and running `docker compose up -d` +Two buttons are provided. These buttons create and delete an index called `moviequotes`. +If you are not running elasticsearch on localhost and port 9200, simply load the configuration, +and edit the configuration before using these buttons. + +If you use docker, you can use this [docker-compose](docker-compose.yml) file to start elasticsearch +and kibana by downloading it and running `docker compose up -d`. Important: **make sure your elasticsearch server is configured to send CORS headers**. Without this your browser will not allow requests to Elasticsearch. diff --git a/src/jsMain/resources/privacy.md b/src/jsMain/resources/privacy.md index 8cb28ee..2e7588e 100644 --- a/src/jsMain/resources/privacy.md +++ b/src/jsMain/resources/privacy.md @@ -4,7 +4,7 @@ This tool is designed to not leak any of your information, including any personal information as defined under the GDPR. When you run Rankquest Studio, it runs in your browser. -Except for search plugins, this application does not make any network requests. There is no Ranquest server. There is no server side database. +Except for the search plugins, this application does not make any network requests. There is no Ranquest server. There is no server side database. ## Cookies and Browser Local Storage @@ -12,11 +12,11 @@ This application stores configuration, rated searches, etc. in the browser local ## No Analytics -We currently don't use web analytics (Google analytics or similar). All cookies, localstorage, etc. in the app are used only for the core functionality of this application. Should this change in the future, we will update this policy. +This application currently does not use any web analytics (Google analytics or similar). All cookies, localstorage, etc. in the app are used only for the core functionality of this application. Should this change in the future, we will update this policy. -Requests to the webserver to fetch the assets related to this website may be logged by the hosting provider. Rankquest Studio is currently hosted by [Versio](https://www.versio.nl). You may of course self host rankquest on your own server. +Requests to the webserver to fetch the assets related to this website are logged by the hosting provider. Rankquest Studio is currently hosted by [Versio](https://www.versio.nl). You can of course self host rankquest on your own server. Simply download and build the source code from [Github](https://github.com/jillesvangurp/rankquest-studio). ## Network traffic The included search plugins of course make requests to any search services that you configure. Always make sure you have -the permission from the owners of these services to make such requests. Running metrics can impose a significant load on a server. \ No newline at end of file +the permission from the owners of these services to make such requests. Running metrics may impose a significant load on a server. \ No newline at end of file