feat: initial commit.
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
index/
|
||||||
|
target/
|
||||||
Generated
+1407
File diff suppressed because it is too large
Load Diff
+11
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "search"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.104"
|
||||||
|
clap = { version = "4.6.6", features = ["derive"] }
|
||||||
|
serde = { version = "1.0.229", features = ["derive"] }
|
||||||
|
serde_yaml = "0.9.34"
|
||||||
|
tantivy = "0.26.1"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Search with tantivy
|
||||||
|
|
||||||
|
This demo takes the base_data.yml, indexes it and provides
|
||||||
|
a search in this data.
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
Create an index directory and then execute the indexing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir index
|
||||||
|
cargo run -- index
|
||||||
|
```
|
||||||
|
|
||||||
|
## Search
|
||||||
|
|
||||||
|
Afterwards you can search in the index.
|
||||||
|
It will return a score and the result as JSON.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo run -- search "jazz music"
|
||||||
|
[3.699133] {"description":["Jazzy music with some rainy atmosphere"],"id":["0004"],"title":["I am currently listening to Jazz"]}
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
- id: "0001"
|
||||||
|
title: "Here are some words"
|
||||||
|
description: "An entry with some words"
|
||||||
|
- id: "0002"
|
||||||
|
title: "Something about birds"
|
||||||
|
description: "I have seen some ducks yesterday"
|
||||||
|
- id: "0003"
|
||||||
|
title: "My curtains are gray"
|
||||||
|
description: "Those curtains are blocking light"
|
||||||
|
- id: "0004"
|
||||||
|
title: "I am currently listening to Jazz"
|
||||||
|
description: "Jazzy music with some rainy atmosphere"
|
||||||
|
- id: "0005"
|
||||||
|
title: "Drinking some sugarless products"
|
||||||
|
description: "Naming it would be marketing"
|
||||||
|
- id: "0006"
|
||||||
|
title: "Connected some lan cables today"
|
||||||
|
description: "Working with CAT 6"
|
||||||
|
- id: "0007"
|
||||||
|
title: "I should have used AI to generate this"
|
||||||
|
description: "On the other side, this is some creative work"
|
||||||
|
- id: "0008"
|
||||||
|
title: "But does this work make sense?"
|
||||||
|
description: "What in life does make sense?"
|
||||||
|
- id: "0009"
|
||||||
|
title: "Philosophy"
|
||||||
|
description: "Something about Epictetus"
|
||||||
|
- id: "0010"
|
||||||
|
title: "The last sentence"
|
||||||
|
description: "On how to dump data out of your head"
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
use anyhow::{Context, Result};
|
||||||
|
use clap::Parser;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tantivy::{
|
||||||
|
DocAddress, Document, Index, IndexReader, IndexWriter, Score, TantivyDocument,
|
||||||
|
collector::TopDocs,
|
||||||
|
doc,
|
||||||
|
query::QueryParser,
|
||||||
|
schema::{Field, STORED, STRING, Schema, TEXT},
|
||||||
|
};
|
||||||
|
|
||||||
|
const BASE_DATA: &str = include_str!("../base_data.yml");
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
enum Args {
|
||||||
|
#[command(about = "Build an index")]
|
||||||
|
Index,
|
||||||
|
#[command(about = "Execute the search")]
|
||||||
|
Search {
|
||||||
|
#[arg(help = "A search query")]
|
||||||
|
search: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct BaseDataEntry {
|
||||||
|
id: String,
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IndexData {
|
||||||
|
index: Index,
|
||||||
|
schema: Schema,
|
||||||
|
id: Field,
|
||||||
|
title: Field,
|
||||||
|
description: Field,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
match args {
|
||||||
|
Args::Index => execute_index(),
|
||||||
|
Args::Search { search } => execute_search(search),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_index_data(create: bool) -> Result<IndexData> {
|
||||||
|
let mut schema_builder = Schema::builder();
|
||||||
|
|
||||||
|
let id = schema_builder.add_text_field("id", STRING | STORED);
|
||||||
|
let title = schema_builder.add_text_field("title", TEXT | STORED);
|
||||||
|
let description = schema_builder.add_text_field("description", TEXT | STORED);
|
||||||
|
|
||||||
|
let schema = schema_builder.build();
|
||||||
|
let index = match create {
|
||||||
|
true => {
|
||||||
|
Index::create_in_dir("index", schema.clone()).context("Creating index in directory")?
|
||||||
|
}
|
||||||
|
false => Index::open_in_dir("index").context("Opening index in directory")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(IndexData {
|
||||||
|
index,
|
||||||
|
schema,
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_index() -> Result<()> {
|
||||||
|
let index_data = build_index_data(true)?;
|
||||||
|
let index = index_data.index;
|
||||||
|
let id = index_data.id;
|
||||||
|
let title = index_data.title;
|
||||||
|
let description = index_data.description;
|
||||||
|
|
||||||
|
let mut index_writer: IndexWriter = index
|
||||||
|
.writer(100_000_000)
|
||||||
|
.context("Create an index writer")?;
|
||||||
|
|
||||||
|
let base_data: Vec<BaseDataEntry> = serde_yaml::from_str(BASE_DATA)?;
|
||||||
|
for data in base_data {
|
||||||
|
index_writer.add_document(doc!(
|
||||||
|
id => data.id,
|
||||||
|
title => data.title,
|
||||||
|
description => data.description,
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
index_writer.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_search(search: String) -> Result<()> {
|
||||||
|
let index_data = build_index_data(false)?;
|
||||||
|
let index = index_data.index;
|
||||||
|
let schema = index_data.schema;
|
||||||
|
let id = index_data.id;
|
||||||
|
let title = index_data.title;
|
||||||
|
let description = index_data.description;
|
||||||
|
|
||||||
|
let index_reader: IndexReader = index.reader().context("Create an index reader")?;
|
||||||
|
let searcher = index_reader.searcher();
|
||||||
|
let query_parser = QueryParser::for_index(&index, vec![id, title, description]);
|
||||||
|
|
||||||
|
let query = query_parser.parse_query(&search)?;
|
||||||
|
let top_docs: Vec<(Score, DocAddress)> =
|
||||||
|
searcher.search(&query, &TopDocs::with_limit(10).order_by_score())?;
|
||||||
|
|
||||||
|
for (score, doc_address) in top_docs {
|
||||||
|
let retrieved_doc = searcher.doc::<TantivyDocument>(doc_address)?;
|
||||||
|
println!("[{}] {}", score, retrieved_doc.to_json(&schema));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user