Skip to content

Commit d604317

Browse files
authored
explicit error if v1/search requests a table without search index (spiceai#10968)
1 parent 51dc129 commit d604317

4 files changed

Lines changed: 61 additions & 1 deletion

File tree

crates/runtime/src/http/v1/search.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ pub(crate) async fn post(
207207
Err(e) => {
208208
let error_type = match e {
209209
VectorSearchError::NoTablesWithSearchFound {}
210-
| VectorSearchError::CannotVectorSearchDataset { .. } => StatusCode::BAD_REQUEST,
210+
| VectorSearchError::CannotVectorSearchDataset { .. }
211+
| VectorSearchError::CannotSearchDataset { .. } => StatusCode::BAD_REQUEST,
211212
VectorSearchError::SearchPipelineError { ref source } if source.is_user_error() => {
212213
StatusCode::BAD_REQUEST
213214
}

crates/runtime/src/search/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ pub enum Error {
4646
#[snafu(display("Vector search cannot be run on {}.", data_source.to_quoted_string()))]
4747
CannotVectorSearchDataset { data_source: TableReference },
4848

49+
#[snafu(display(
50+
"Search cannot be run on {} because it has no embeddings or full text search indexes.",
51+
data_source.to_quoted_string()
52+
))]
53+
CannotSearchDataset { data_source: TableReference },
54+
4955
#[snafu(display("Failed to execute search query: {}", format_datafusion_error(source)))]
5056
DataFusionError {
5157
source: datafusion::error::DataFusionError,

crates/runtime/src/search/search_engine.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ impl SearchEngine {
321321
additional_columns,
322322
keywords,
323323
} = req;
324+
let explicit_datasets_requested = data_source_opt.is_some();
324325

325326
let tables = match data_source_opt {
326327
Some(ts) => ts.iter().map(TableReference::from).collect(),
@@ -369,6 +370,12 @@ impl SearchEngine {
369370
generators.append(&mut fts);
370371
}
371372

373+
if explicit_datasets_requested && generators.is_empty() {
374+
return Err(Error::CannotSearchDataset {
375+
data_source: tbl.clone(),
376+
});
377+
}
378+
372379
// Ensure columns for a specific table aren't used on all tables.
373380
let table_cols: Vec<_> = additional_columns
374381
.iter()

crates/runtime/tests/models/search.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,52 @@ async fn test_text_search() -> Result<(), anyhow::Error> {
16311631
.await
16321632
}
16331633

1634+
#[tokio::test]
1635+
async fn test_explicit_dataset_searchability_validation() -> Result<(), anyhow::Error> {
1636+
run_search(
1637+
AppBuilder::new("search_app")
1638+
.with_dataset(get_mega_science_dataset(
1639+
Some("searchable"),
1640+
None,
1641+
Some(
1642+
Column::new("answer")
1643+
.with_full_text_search(FullTextSearchConfig::enabled().with_row_id("id")),
1644+
),
1645+
))
1646+
.with_dataset(get_mega_science_dataset(Some("plain"), None, None))
1647+
.build(),
1648+
vec![
1649+
SearchTestCase::new(
1650+
"explicit_non_searchable_dataset_errors",
1651+
SearchTestType::Http(json!({
1652+
"text": "second",
1653+
"limit": 4,
1654+
"datasets": ["plain"],
1655+
})),
1656+
)
1657+
.should_fail(),
1658+
SearchTestCase::new(
1659+
"explicit_mixed_datasets_fail_fast",
1660+
SearchTestType::Http(json!({
1661+
"text": "second",
1662+
"limit": 4,
1663+
"datasets": ["searchable", "plain"],
1664+
})),
1665+
)
1666+
.should_fail(),
1667+
SearchTestCase::new(
1668+
"explicit_searchable_dataset_no_matches_returns_empty",
1669+
SearchTestType::Http(json!({
1670+
"text": "query-that-will-not-match-any-megascience-row-xyz",
1671+
"limit": 4,
1672+
"datasets": ["searchable"],
1673+
})),
1674+
),
1675+
],
1676+
)
1677+
.await
1678+
}
1679+
16341680
#[tokio::test]
16351681
async fn test_text_search_view() -> Result<(), anyhow::Error> {
16361682
let (ds, views) = get_mega_science_view(

0 commit comments

Comments
 (0)