Skip to content

Commit

Permalink
feat(WIP): alter fulltext index
Browse files Browse the repository at this point in the history
Co-Authored-By: irenjj <renj.jiang@gmail.com>
  • Loading branch information
CookiePieWw and irenjj committed Nov 6, 2024
1 parent cccd25d commit 809abdb
Show file tree
Hide file tree
Showing 25 changed files with 909 additions and 402 deletions.
894 changes: 580 additions & 314 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ etcd-client = { version = "0.13" }
fst = "0.4.7"
futures = "0.3"
futures-util = "0.3"
greptime-proto = { git = "https://github.com/GreptimeTeam/greptime-proto.git", rev = "255f87a3318ace3f88a67f76995a0e14910983f4" }
greptime-proto = { git = "https://github.com/CookiePieWw/greptime-proto.git", rev = "6ca31389810e1385a4887469ea96f521b2f4180c" }
humantime = "2.1"
humantime-serde = "1.1"
itertools = "0.10"
Expand Down
14 changes: 13 additions & 1 deletion src/api/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ pub enum Error {
source: datatypes::error::Error,
},

#[snafu(display(
"Invalid fulltext analyzer, given analyzer: {:?}, expect 0 for English and 1 for Chinese ",
analyzer
))]
InvalidFulltextAnalyzer {
#[snafu(implicit)]
location: Location,
analyzer: i32,
},

#[snafu(display("Failed to serialize JSON"))]
SerializeJson {
#[snafu(source)]
Expand All @@ -71,7 +81,9 @@ pub enum Error {
impl ErrorExt for Error {
fn status_code(&self) -> StatusCode {
match self {
Error::UnknownColumnDataType { .. } => StatusCode::InvalidArguments,
Error::UnknownColumnDataType { .. } | Error::InvalidFulltextAnalyzer { .. } => {
StatusCode::InvalidArguments
}
Error::IntoColumnDataType { .. } | Error::SerializeJson { .. } => {
StatusCode::Unexpected
}
Expand Down
12 changes: 11 additions & 1 deletion src/api/src/v1/column_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
use std::collections::HashMap;

use datatypes::schema::{
ColumnDefaultConstraint, ColumnSchema, FulltextOptions, COMMENT_KEY, FULLTEXT_KEY,
ColumnDefaultConstraint, ColumnSchema, FulltextAnalyzer, FulltextOptions, COMMENT_KEY,
FULLTEXT_KEY,
};
use snafu::ResultExt;

Expand Down Expand Up @@ -93,6 +94,15 @@ pub fn options_from_fulltext(fulltext: &FulltextOptions) -> Result<Option<Column
Ok((!options.options.is_empty()).then_some(options))
}

/// Tries to construct a `FulltextAnalyzer` from the given analyzer.
pub fn try_as_fulltext_option(analyzer: i32) -> Result<FulltextAnalyzer> {
match analyzer {
0 => Ok(FulltextAnalyzer::English),
1 => Ok(FulltextAnalyzer::Chinese),
_ => error::InvalidFulltextAnalyzerSnafu { analyzer }.fail(),
}
}

#[cfg(test)]
mod tests {

Expand Down
17 changes: 14 additions & 3 deletions src/common/grpc-expr/src/alter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@
use api::helper::ColumnDataTypeWrapper;
use api::v1::add_column_location::LocationType;
use api::v1::alter_expr::Kind;
use api::v1::column_def::try_as_fulltext_option;
use api::v1::{
column_def, AddColumnLocation as Location, AlterExpr, ChangeColumnTypes, CreateTableExpr,
DropColumns, RenameTable, SemanticType,
};
use common_query::AddColumnLocation;
use datatypes::schema::{ColumnSchema, RawSchema};
use datatypes::schema::{ColumnSchema, FulltextOptions, RawSchema};
use snafu::{ensure, OptionExt, ResultExt};
use store_api::region_request::ChangeOption;
use table::metadata::TableId;
use table::requests::{AddColumnRequest, AlterKind, AlterTableRequest, ChangeColumnTypeRequest};

use crate::error::{
InvalidChangeTableOptionRequestSnafu, InvalidColumnDefSnafu, MissingFieldSnafu,
MissingTimestampColumnSnafu, Result, UnknownLocationTypeSnafu,
InvalidChangeFulltextOptionRequestSnafu, InvalidChangeTableOptionRequestSnafu,
InvalidColumnDefSnafu, MissingFieldSnafu, MissingTimestampColumnSnafu, Result,
UnknownLocationTypeSnafu,
};

const LOCATION_TYPE_FIRST: i32 = LocationType::First as i32;
Expand Down Expand Up @@ -102,6 +104,15 @@ pub fn alter_expr_to_request(table_id: TableId, expr: AlterExpr) -> Result<Alter
.collect::<std::result::Result<Vec<_>, _>>()
.context(InvalidChangeTableOptionRequestSnafu)?,
},
Kind::ChangeColumnFulltext(c) => AlterKind::ChangeColumnFulltext {
column_name: c.column_name.clone(),
options: FulltextOptions {
enable: c.enable,
analyzer: try_as_fulltext_option(c.analyzer)
.context(InvalidChangeFulltextOptionRequestSnafu)?,
case_sensitive: c.case_sensitive,
},
},
};

let request = AlterTableRequest {
Expand Down
9 changes: 8 additions & 1 deletion src/common/grpc-expr/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ pub enum Error {
#[snafu(source)]
error: MetadataError,
},

#[snafu(display("Invalid change fulltext option request"))]
InvalidChangeFulltextOptionRequest {
#[snafu(source)]
error: api::error::Error,
},
}

pub type Result<T> = std::result::Result<T, Error>;
Expand All @@ -148,7 +154,8 @@ impl ErrorExt for Error {
Error::UnknownColumnDataType { .. } | Error::InvalidFulltextColumnType { .. } => {
StatusCode::InvalidArguments
}
Error::InvalidChangeTableOptionRequest { .. } => StatusCode::InvalidArguments,
Error::InvalidChangeTableOptionRequest { .. }
| Error::InvalidChangeFulltextOptionRequest { .. } => StatusCode::InvalidArguments,
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/common/meta/src/ddl/alter_table/region_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ fn create_proto_alter_kind(
}
Kind::RenameTable(_) => Ok(None),
Kind::ChangeTableOptions(v) => Ok(Some(alter_request::Kind::ChangeTableOptions(v.clone()))),
Kind::ChangeColumnFulltext(v) => {
Ok(Some(alter_request::Kind::ChangeColumnFulltext(v.clone())))
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/common/meta/src/ddl/alter_table/update_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ impl AlterTableProcedure {
}
AlterKind::DropColumns { .. }
| AlterKind::ChangeColumnTypes { .. }
| AlterKind::ChangeTableOptions { .. } => {}
| AlterKind::ChangeTableOptions { .. }
| AlterKind::ChangeColumnFulltext { .. } => {}
}

Ok(new_info)
Expand Down
2 changes: 2 additions & 0 deletions src/datatypes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ paste = "1.0"
serde.workspace = true
serde_json.workspace = true
snafu.workspace = true
sqlparser.workspace = true
sqlparser_derive = "0.1"
10 changes: 9 additions & 1 deletion src/datatypes/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,13 @@ pub enum Error {
#[snafu(implicit)]
location: Location,
},

#[snafu(display("Invalid fulltext option: {}", msg))]
InvalidFulltextOption {
msg: String,
#[snafu(implicit)]
location: Location,
},
}

impl ErrorExt for Error {
Expand All @@ -230,7 +237,8 @@ impl ErrorExt for Error {
| DuplicateMeta { .. }
| InvalidTimestampPrecision { .. }
| InvalidPrecisionOrScale { .. }
| InvalidJson { .. } => StatusCode::InvalidArguments,
| InvalidJson { .. }
| InvalidFulltextOption { .. } => StatusCode::InvalidArguments,

ValueExceedsPrecision { .. }
| CastType { .. }
Expand Down
5 changes: 3 additions & 2 deletions src/datatypes/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use snafu::{ensure, ResultExt};
use crate::error::{self, DuplicateColumnSnafu, Error, ProjectArrowSchemaSnafu, Result};
use crate::prelude::DataType;
pub use crate::schema::column_schema::{
ColumnSchema, FulltextAnalyzer, FulltextOptions, Metadata, COMMENT_KEY, FULLTEXT_KEY,
TIME_INDEX_KEY,
ColumnSchema, FulltextAnalyzer, FulltextOptions, Metadata,
COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE, COLUMN_FULLTEXT_OPT_KEY_ANALYZER,
COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE, COMMENT_KEY, FULLTEXT_KEY, TIME_INDEX_KEY,
};
pub use crate::schema::constraint::ColumnDefaultConstraint;
pub use crate::schema::raw::RawSchema;
Expand Down
75 changes: 72 additions & 3 deletions src/datatypes/src/schema/column_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ use std::fmt;
use arrow::datatypes::Field;
use serde::{Deserialize, Serialize};
use snafu::{ensure, ResultExt};
use sqlparser_derive::{Visit, VisitMut};

use crate::data_type::{ConcreteDataType, DataType};
use crate::error::{self, Error, Result};
use crate::error::{self, Error, InvalidFulltextOptionSnafu, Result};
use crate::schema::constraint::ColumnDefaultConstraint;
use crate::schema::TYPE_KEY;
use crate::types::JSON_TYPE_NAME;
Expand All @@ -37,6 +38,11 @@ const DEFAULT_CONSTRAINT_KEY: &str = "greptime:default_constraint";
/// Key used to store fulltext options in arrow field's metadata.
pub const FULLTEXT_KEY: &str = "greptime:fulltext";

/// Key used in fulltext options
pub const COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE: &str = "enable";
pub const COLUMN_FULLTEXT_OPT_KEY_ANALYZER: &str = "analyzer";
pub const COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE: &str = "case_sensitive";

/// Schema of a column, used as an immutable struct.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ColumnSchema {
Expand Down Expand Up @@ -328,7 +334,7 @@ impl TryFrom<&ColumnSchema> for Field {
}

/// Fulltext options for a column.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Visit, VisitMut)]
#[serde(rename_all = "kebab-case")]
pub struct FulltextOptions {
/// Whether the fulltext index is enabled.
Expand All @@ -341,8 +347,71 @@ pub struct FulltextOptions {
pub case_sensitive: bool,
}

impl fmt::Display for FulltextOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "enable: {}", self.enable)?;
if self.enable {
write!(f, ", analyzer: {}", self.analyzer)?;
write!(f, ", case_sensitive: {}", self.case_sensitive)?;
}
Ok(())
}
}

impl TryFrom<HashMap<String, String>> for FulltextOptions {
type Error = crate::error::Error;

fn try_from(options: HashMap<String, String>) -> Result<Self> {
let mut fulltext_options = FulltextOptions {
enable: true,
..Default::default()
};

if let Some(enable) = options.get(COLUMN_FULLTEXT_CHANGE_OPT_KEY_ENABLE) {
match enable.to_ascii_lowercase().as_str() {
"true" => fulltext_options.enable = true,
"false" => fulltext_options.enable = false,
_ => {
return InvalidFulltextOptionSnafu {
msg: format!("{enable}, expected: 'true' | 'false'"),
}
.fail();
}
}
};

if let Some(analyzer) = options.get(COLUMN_FULLTEXT_OPT_KEY_ANALYZER) {
match analyzer.to_ascii_lowercase().as_str() {
"english" => fulltext_options.analyzer = FulltextAnalyzer::English,
"chinese" => fulltext_options.analyzer = FulltextAnalyzer::Chinese,
_ => {
return InvalidFulltextOptionSnafu {
msg: format!("{analyzer}, expected: 'English' | 'Chinese'"),
}
.fail();
}
}
};

if let Some(case_sensitive) = options.get(COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE) {
match case_sensitive.to_ascii_lowercase().as_str() {
"true" => fulltext_options.case_sensitive = true,
"false" => fulltext_options.case_sensitive = false,
_ => {
return InvalidFulltextOptionSnafu {
msg: format!("{case_sensitive}, expected: 'true' | 'false'"),
}
.fail();
}
}
}

Ok(fulltext_options)
}
}

/// Fulltext analyzer.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Visit, VisitMut)]
pub enum FulltextAnalyzer {
#[default]
English,
Expand Down
15 changes: 12 additions & 3 deletions src/operator/src/expr_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use api::helper::ColumnDataTypeWrapper;
use api::v1::alter_expr::Kind;
use api::v1::column_def::options_from_column_schema;
use api::v1::{
AddColumn, AddColumns, AlterExpr, ChangeColumnType, ChangeColumnTypes, ChangeTableOptions,
ColumnDataType, ColumnDataTypeExtension, CreateFlowExpr, CreateTableExpr, CreateViewExpr,
DropColumn, DropColumns, ExpireAfter, RenameTable, SemanticType, TableName,
AddColumn, AddColumns, AlterExpr, ChangeColumnFulltext, ChangeColumnType, ChangeColumnTypes,
ChangeTableOptions, ColumnDataType, ColumnDataTypeExtension, CreateFlowExpr, CreateTableExpr,
CreateViewExpr, DropColumn, DropColumns, ExpireAfter, RenameTable, SemanticType, TableName,
};
use common_error::ext::BoxedError;
use common_grpc_expr::util::ColumnExpr;
Expand Down Expand Up @@ -488,6 +488,15 @@ pub(crate) fn to_alter_expr(
change_table_options: options.into_iter().map(Into::into).collect(),
})
}
AlterTableOperation::ChangeColumnFulltext {
column_name,
options,
} => Kind::ChangeColumnFulltext(ChangeColumnFulltext {
column_name: column_name.value.to_string(),
enable: options.enable,
analyzer: options.analyzer as i32,
case_sensitive: options.case_sensitive,
}),
};

Ok(AlterExpr {
Expand Down
6 changes: 4 additions & 2 deletions src/query/src/sql/show_create_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
use std::collections::HashMap;

use common_meta::SchemaOptions;
use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema, SchemaRef, COMMENT_KEY};
use datatypes::schema::{
ColumnDefaultConstraint, ColumnSchema, SchemaRef, COLUMN_FULLTEXT_OPT_KEY_ANALYZER,
COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE, COMMENT_KEY,
};
use humantime::format_duration;
use snafu::ResultExt;
use sql::ast::{
Expand All @@ -27,7 +30,6 @@ use sql::dialect::GreptimeDbDialect;
use sql::parser::ParserContext;
use sql::statements::create::{Column, ColumnExtensions, CreateTable, TIME_INDEX};
use sql::statements::{self, OptionMap};
use sql::{COLUMN_FULLTEXT_OPT_KEY_ANALYZER, COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE};
use sqlparser::ast::KeyOrIndexDisplay;
use store_api::metric_engine_consts::{is_metric_engine, is_metric_engine_internal_column};
use table::metadata::{TableInfoRef, TableMeta};
Expand Down
4 changes: 1 addition & 3 deletions src/sql/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ pub mod parsers;
pub mod statements;
pub mod util;

pub use parsers::create_parser::{
COLUMN_FULLTEXT_OPT_KEY_ANALYZER, COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE, ENGINE, MAXVALUE,
};
pub use parsers::create_parser::{ENGINE, MAXVALUE};
pub use parsers::tql_parser::TQL;
pub use statements::create::TIME_INDEX;
Loading

0 comments on commit 809abdb

Please sign in to comment.