lance_file/versions/v1/encoding/
dictionary.rs1use std::fmt;
8use std::sync::Arc;
9
10use arrow_array::cast::{as_dictionary_array, as_primitive_array};
11use arrow_array::types::{
12 ArrowDictionaryKeyType, Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type, UInt16Type,
13 UInt32Type, UInt64Type,
14};
15use arrow_array::{Array, ArrayRef, DictionaryArray, PrimitiveArray, UInt32Array};
16use arrow_schema::DataType;
17
18use lance_core::{Error, Result};
19use lance_io::{
20 ReadBatchParams,
21 traits::{Reader, Writer},
22};
23
24use super::plain::{PlainDecoder, PlainEncoder};
25
26pub struct DictionaryEncoder<'a> {
28 writer: &'a mut dyn Writer,
29 key_type: &'a DataType,
30}
31
32impl<'a> DictionaryEncoder<'a> {
33 pub fn new(writer: &'a mut dyn Writer, key_type: &'a DataType) -> Self {
34 Self { writer, key_type }
35 }
36
37 async fn write_typed_array<T: ArrowDictionaryKeyType>(
38 &mut self,
39 arrs: &[&dyn Array],
40 ) -> Result<usize> {
41 assert!(!arrs.is_empty());
42 let data_type = arrs[0].data_type();
43 let pos = self.writer.tell().await?;
44 let mut plain_encoder = PlainEncoder::new(self.writer, data_type);
45
46 let keys = arrs
47 .iter()
48 .map(|a| {
49 let dict_arr = as_dictionary_array::<T>(*a);
50 dict_arr.keys() as &dyn Array
51 })
52 .collect::<Vec<_>>();
53
54 plain_encoder.encode(keys.as_slice()).await?;
55 Ok(pos)
56 }
57}
58
59impl DictionaryEncoder<'_> {
60 pub async fn encode(&mut self, array: &[&dyn Array]) -> Result<usize> {
61 use DataType::*;
62
63 match self.key_type {
64 UInt8 => self.write_typed_array::<UInt8Type>(array).await,
65 UInt16 => self.write_typed_array::<UInt16Type>(array).await,
66 UInt32 => self.write_typed_array::<UInt32Type>(array).await,
67 UInt64 => self.write_typed_array::<UInt64Type>(array).await,
68 Int8 => self.write_typed_array::<Int8Type>(array).await,
69 Int16 => self.write_typed_array::<Int16Type>(array).await,
70 Int32 => self.write_typed_array::<Int32Type>(array).await,
71 Int64 => self.write_typed_array::<Int64Type>(array).await,
72 _ => Err(Error::schema(format!(
73 "DictionaryEncoder: unsupported key type: {:?}",
74 self.key_type
75 ))),
76 }
77 }
78}
79
80pub struct DictionaryDecoder<'a> {
82 reader: &'a dyn Reader,
83 position: usize,
85 length: usize,
87 data_type: &'a DataType,
89 value_arr: ArrayRef,
91}
92
93impl fmt::Debug for DictionaryDecoder<'_> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 f.debug_struct("DictionaryDecoder")
96 .field("position", &self.position)
97 .field("length", &self.length)
98 .field("data_type", &self.data_type)
99 .field("value_arr", &self.value_arr)
100 .finish()
101 }
102}
103
104impl<'a> DictionaryDecoder<'a> {
105 pub fn new(
106 reader: &'a dyn Reader,
107 position: usize,
108 length: usize,
109 data_type: &'a DataType,
110 value_arr: ArrayRef,
111 ) -> Self {
112 assert!(matches!(data_type, DataType::Dictionary(_, _)));
113 Self {
114 reader,
115 position,
116 length,
117 data_type,
118 value_arr,
119 }
120 }
121
122 async fn decode_impl(&self, params: impl Into<ReadBatchParams>) -> Result<ArrayRef> {
123 let index_type = if let DataType::Dictionary(key_type, _) = &self.data_type {
124 assert!(key_type.as_ref().is_dictionary_key_type());
125 key_type.as_ref()
126 } else {
127 return Err(Error::arrow(format!(
128 "Not a dictionary type: {}",
129 self.data_type
130 )));
131 };
132
133 let decoder = PlainDecoder::new(self.reader, index_type, self.position, self.length)?;
134 let keys = decoder.get(params.into()).await?;
135
136 match index_type {
137 DataType::Int8 => self.make_dict_array::<Int8Type>(keys).await,
138 DataType::Int16 => self.make_dict_array::<Int16Type>(keys).await,
139 DataType::Int32 => self.make_dict_array::<Int32Type>(keys).await,
140 DataType::Int64 => self.make_dict_array::<Int64Type>(keys).await,
141 DataType::UInt8 => self.make_dict_array::<UInt8Type>(keys).await,
142 DataType::UInt16 => self.make_dict_array::<UInt16Type>(keys).await,
143 DataType::UInt32 => self.make_dict_array::<UInt32Type>(keys).await,
144 DataType::UInt64 => self.make_dict_array::<UInt64Type>(keys).await,
145 _ => Err(Error::arrow(format!(
146 "Dictionary encoding does not support index type: {index_type}",
147 ))),
148 }
149 }
150
151 async fn make_dict_array<T: ArrowDictionaryKeyType + Sync + Send>(
152 &self,
153 index_array: ArrayRef,
154 ) -> Result<ArrayRef> {
155 let keys: PrimitiveArray<T> = as_primitive_array(index_array.as_ref()).clone();
156 Ok(Arc::new(DictionaryArray::try_new(
157 keys,
158 self.value_arr.clone(),
159 )?))
160 }
161}
162
163impl DictionaryDecoder<'_> {
164 pub async fn decode(&self) -> Result<ArrayRef> {
165 self.decode_impl(..).await
166 }
167
168 pub async fn take(&self, indices: &UInt32Array) -> Result<ArrayRef> {
169 self.decode_impl(indices.clone()).await
170 }
171
172 pub async fn get(&self, params: impl Into<ReadBatchParams>) -> Result<ArrayRef> {
173 self.decode_impl(params).await
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 use arrow_array::StringArray;
182 use arrow_buffer::ArrowNativeType;
183 use lance_core::utils::tempfile::TempStdFile;
184 use lance_io::local::LocalObjectReader;
185 use tokio::io::AsyncWriteExt;
186
187 async fn test_dict_decoder_for_type<T: ArrowDictionaryKeyType>() {
188 let value_array: StringArray = vec![Some("a"), Some("b"), Some("c"), Some("d")]
189 .into_iter()
190 .collect();
191 let value_array_ref = Arc::new(value_array) as ArrayRef;
192
193 let keys1: PrimitiveArray<T> = vec![T::Native::from_usize(0), T::Native::from_usize(1)]
194 .into_iter()
195 .collect();
196 let arr1: DictionaryArray<T> =
197 DictionaryArray::try_new(keys1, value_array_ref.clone()).unwrap();
198
199 let keys2: PrimitiveArray<T> = vec![T::Native::from_usize(1), T::Native::from_usize(3)]
200 .into_iter()
201 .collect();
202 let arr2: DictionaryArray<T> =
203 DictionaryArray::try_new(keys2, value_array_ref.clone()).unwrap();
204
205 let keys1_ref = arr1.keys() as &dyn Array;
206 let keys2_ref = arr2.keys() as &dyn Array;
207 let arrs: Vec<&dyn Array> = vec![keys1_ref, keys2_ref];
208
209 let path = TempStdFile::default();
210
211 let pos;
212 {
213 let mut object_writer = tokio::fs::File::create(&path).await.unwrap();
214 let mut encoder = PlainEncoder::new(&mut object_writer, arr1.keys().data_type());
215 pos = encoder.encode(arrs.as_slice()).await.unwrap();
216 AsyncWriteExt::shutdown(&mut object_writer).await.unwrap();
217 }
218
219 let reader = LocalObjectReader::open_local_path(&path, 2048, None)
220 .await
221 .unwrap();
222 let decoder = DictionaryDecoder::new(
223 reader.as_ref(),
224 pos,
225 arr1.len() + arr2.len(),
226 arr1.data_type(),
227 value_array_ref.clone(),
228 );
229
230 let decoded_data = decoder.decode().await.unwrap();
231 let expected_data: DictionaryArray<T> = vec!["a", "b", "b", "d"].into_iter().collect();
232 assert_eq!(
233 &expected_data,
234 decoded_data
235 .as_any()
236 .downcast_ref::<DictionaryArray<T>>()
237 .unwrap()
238 );
239 }
240
241 #[tokio::test]
242 async fn test_dict_decoder() {
243 test_dict_decoder_for_type::<Int8Type>().await;
244 test_dict_decoder_for_type::<Int16Type>().await;
245 test_dict_decoder_for_type::<Int32Type>().await;
246 test_dict_decoder_for_type::<Int64Type>().await;
247
248 test_dict_decoder_for_type::<UInt8Type>().await;
249 test_dict_decoder_for_type::<UInt16Type>().await;
250 test_dict_decoder_for_type::<UInt32Type>().await;
251 test_dict_decoder_for_type::<UInt64Type>().await;
252 }
253}