-
Notifications
You must be signed in to change notification settings - Fork 505
Adding the complete architecture for search benchmarking #2740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
9c9ab67
creating skeleton for benchmarks starting with creating some test_que…
Rahban1 9018d75
created functions for measuring search performance
Rahban1 71b1e6b
Merge branch 'JuliaDocs:master' into benchmarks
Rahban1 7b828ab
added comments and changes some tests
Rahban1 c533f44
search mockup
Rahban1 fbc226e
creating wrapper.js as seperate file
Rahban1 d750e7d
only install the exact version of minisearch
Rahban1 91d3001
ran runic for linting
Rahban1 044506c
make command
Rahban1 56dc16a
changelog
Rahban1 3dd42ed
Merge branch 'master' into benchmarks
Rahban1 9beb5d2
typo in comments
Rahban1 8b99e46
running benchmarks on ci
Rahban1 3e1954d
building the docs before running benchmarks
Rahban1 fd7891b
fixing the correct position of search index
Rahban1 5f9f074
prettify the output
Rahban1 825ed0c
add color in tables and add PrettyTables in Project.toml
Rahban1 72e616d
added crayons in Project.toml
Rahban1 76a1201
change to @__DIR__ for relative paths
Rahban1 6beae8c
use the search index used in prod
Rahban1 7e8ea88
new queries
Rahban1 4ccb192
full benchmark report is uploaded as an artifact and moved the benchm…
Rahban1 da1f773
ran runic for linting
Rahban1 73144dc
added node setup in CI
Rahban1 0865207
write js code to temp file to get rid of error
Rahban1 8938733
ran runic for linting
Rahban1 b7c2599
removed the redundant npm install logic from test/search/real_search.…
Rahban1 77d08f2
ran the temp file within test/search so it find the minisearch module
Rahban1 ef382cb
ran runic for linting
Rahban1 0f32b37
now the values are compared to a fix set of values everytime it runs
Rahban1 2d08814
ran runic for linting
Rahban1 7ca4173
Merge branch 'master' into benchmarks
Rahban1 cfe1608
Change PrettyTables.jl and Crayons from deps of package to test deps
Rahban1 835513d
version's source of truth is now in HTMLWriter.jl
Rahban1 2b685cf
Merge branch 'master' into benchmarks
Rahban1 f4eaeda
Ran prettier
Rahban1 6a28a67
removed running in matrix in CI.yml
Rahban1 341fc76
adding NodeJLL
Rahban1 dfbdb29
reverting the nodeJLL changes
Rahban1 17348d1
Fix CI by creating package.json on the fly
Rahban1 dd2608e
Changes linux command to fetch the minisearch version
Rahban1 dc68379
Instantiate main project environment
Rahban1 3f32001
chage test/search to use [sources]
mortenpi 8a4d747
Remove CHANGELOG.md as it is not a user-facing change
Rahban1 f9212d8
Not exclude search.js from Documenter.js rather just replacing the pl…
Rahban1 f8c12de
Uses Documenter in real_search.jl and remove the making of package.js…
Rahban1 ec80a78
ran runic for linting
Rahban1 373f3ec
Add prefix to specifically mention to install the npm packages in the…
Rahban1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| [deps] | ||
| Crayons = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" | ||
| Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" | ||
| Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" | ||
| JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" | ||
| NodeJS_22_jll = "8fca9ca2-e7a1-5ccf-8c05-43be5a78664f" | ||
| Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" | ||
| PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" | ||
|
|
||
| [sources] | ||
| Documenter = { path="../.." } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| # Represents the evaluation results for a single search query | ||
| struct QueryResult | ||
| query::String | ||
| precision::Float64 | ||
| recall::Float64 | ||
| f1::Float64 | ||
| expected::Vector{String} | ||
| actual::Vector{String} | ||
| # Raw integer values used in calculations | ||
| relevant_count::Int # Number of relevant documents found | ||
| total_retrieved::Int # Total number of documents retrieved | ||
| total_relevant::Int # Total number of relevant documents | ||
| end | ||
|
|
||
| # Aggregates evaluation results across multiple search queries | ||
| struct EvaluationResults | ||
| individual_results::Vector{QueryResult} | ||
| average_precision::Float64 | ||
| average_recall::Float64 | ||
| average_f1_score::Float64 | ||
| # Raw integer values for overall evaluation | ||
| total_relevant_found::Int # Total number of relevant documents found across all queries | ||
| total_documents_retrieved::Int # Total number of documents retrieved across all queries | ||
| total_relevant_documents::Int # Total number of relevant documents across all queries | ||
| end | ||
|
|
||
| # Calculates precision for search results against expected documents | ||
| # Precision = (relevant documents found) / (total documents retrieved) | ||
| # Returns precision score, count of relevant documents found, and total documents retrieved | ||
| function calculate_precision(results, expected_docs) | ||
| if isempty(results) | ||
| return 0.0, 0, 0 | ||
| end | ||
|
|
||
| relevant_count = length(intersect(results, expected_docs)) | ||
| total_retrieved = length(results) | ||
|
|
||
| return relevant_count / total_retrieved, relevant_count, total_retrieved | ||
| end | ||
|
|
||
| # Calculates recall for search results against expected documents | ||
| # Recall = (relevant documents found) / (total relevant documents) | ||
| # Measures completeness of the search results - how many of the relevant documents were found | ||
| # Returns recall score, count of relevant documents found, and total relevant documents | ||
| function calculate_recall(results, expected_docs) | ||
| if isempty(expected_docs) | ||
| return 1.0, 0, 0 | ||
| end | ||
|
|
||
| found_count = length(intersect(results, expected_docs)) | ||
| total_relevant = length(expected_docs) | ||
|
|
||
| return found_count / total_relevant, found_count, total_relevant | ||
| end | ||
|
|
||
| # Calculates F1 score from precision and recall values | ||
| # F1 = 2 * (precision * recall) / (precision + recall) | ||
| # Combines precision and recall into a single score, giving equal weight to both metrics | ||
| # Returns 0.0 if both precision and recall are 0 | ||
| function calculate_f1(precision, recall) | ||
| if precision + recall == 0 | ||
| return 0.0 | ||
| end | ||
|
|
||
| return 2 * (precision * recall) / (precision + recall) | ||
| end | ||
|
|
||
| # Evaluates a single search query using the provided search function | ||
| # Returns a QueryResult containing precision, recall, and F1 metrics | ||
| function evaluate_query(search_function, query::TestQuery) | ||
| results = search_function(query.query) | ||
|
|
||
| precision, relevant_count, total_retrieved = calculate_precision(results, query.expected_docs) | ||
| recall, found_count, total_relevant = calculate_recall(results, query.expected_docs) | ||
| f1 = calculate_f1(precision, recall) | ||
|
|
||
| return QueryResult( | ||
| query.query, | ||
| precision, | ||
| recall, | ||
| f1, | ||
| query.expected_docs, | ||
| results, | ||
| relevant_count, | ||
| total_retrieved, | ||
| total_relevant | ||
| ) | ||
| end | ||
|
|
||
| # Evaluates multiple search queries and aggregates the results | ||
| # Returns an EvaluationResults containing average metrics across all queries | ||
| function evaluate_all(search_function, queries) | ||
| results = [evaluate_query(search_function, q) for q in queries] | ||
|
|
||
| avg_precision = mean([r.precision for r in results]) | ||
| avg_recall = mean([r.recall for r in results]) | ||
| avg_f1 = mean([r.f1 for r in results]) | ||
|
|
||
| # Calculate total raw values across all queries | ||
| total_relevant_found = sum(r.relevant_count for r in results) | ||
| total_documents_retrieved = sum(r.total_retrieved for r in results) | ||
| total_relevant_documents = sum(r.total_relevant for r in results) | ||
|
|
||
| return EvaluationResults( | ||
| results, | ||
| avg_precision, | ||
| avg_recall, | ||
| avg_f1, | ||
| total_relevant_found, | ||
| total_documents_retrieved, | ||
| total_relevant_documents | ||
| ) | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| using JSON | ||
| using NodeJS_22_jll | ||
| using Documenter | ||
|
|
||
| # Load the real search index from test examples (already built!) | ||
| function load_real_search_index() | ||
| # Use the example search index that's already built and tested | ||
| search_index_path = joinpath(@__DIR__, "../../docs/build/search_index.js") | ||
|
|
||
| if !isfile(search_index_path) | ||
| error("Search index not found at: $search_index_path") | ||
| end | ||
|
|
||
| # Read and parse the JavaScript file | ||
| content = read(search_index_path, String) | ||
|
|
||
| # Find the JSON data after "var documenterSearchIndex = " | ||
| json_start = findfirst("var documenterSearchIndex = ", content) | ||
| if json_start === nothing | ||
| error("Invalid search index format: missing variable declaration") | ||
| end | ||
|
|
||
| # Extract JSON content (everything after the variable declaration) | ||
| json_content = content[(last(json_start) + 1):end] | ||
|
|
||
| # Parse the JSON | ||
| parsed = JSON.parse(json_content) | ||
| return parsed["docs"] # Return just the docs array | ||
| end | ||
|
|
||
| # Simple function that uses the existing search.js with real search data | ||
| function real_search(query::String) | ||
| # Load the real search index automatically | ||
| search_index_data = load_real_search_index() | ||
|
|
||
| # Read the JS wrapper and inject data | ||
| wrapper_js = read(joinpath(@__DIR__, "wrapper.js"), String) | ||
| wrapper_js = replace(wrapper_js, "__SEARCH_INDEX__" => JSON.json(search_index_data)) | ||
| wrapper_js = replace(wrapper_js, "__QUERY__" => "\"" * query * "\"") | ||
mortenpi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| # Write the wrapper to a temporary file and run it | ||
| return mktemp(@__DIR__) do path, io | ||
| write(io, wrapper_js) | ||
| close(io) | ||
| cd(@__DIR__) do | ||
| # Install minisearch if it's not there | ||
| if !isdir("node_modules") || !isfile("node_modules/minisearch/package.json") | ||
| version = Documenter.HTMLWriter.MINISEARCH_VERSION | ||
| if version === nothing | ||
| error("Could not find minisearch version in search.js") | ||
| end | ||
| # We have to pass --prefix here, otherwise npm might try to install | ||
| # minisearch in a different location depending on the environment. | ||
| run(`$(NodeJS_22_jll.npm) --prefix . install minisearch@$(version)`) | ||
| end | ||
| result = read(`$(NodeJS_22_jll.node) $path`, String) | ||
| return JSON.parse(strip(result)) | ||
| end | ||
| end | ||
| end | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.