In this recorded Fast Focus Live! 360 session with Buck Woody, you’ll learn a practical way to cut through data tool overload by starting with the problem—not the technology. Buck shows how to classify workloads, separate transactional needs from analytics and AI, and make platform choices that align with real business value.
You’ll also learn a simple set of filters to evaluate options and a lightweight decision loop you can use to keep your data architecture adaptable as your environment changes.
🔑 What You’ll Learn
• How to recognize the “data paradox”: too many tools, not enough clarity
• The difference between strategy and tactics for data and analytics projects
• How to classify workloads into three pillars: Online transition Processing (OLTP), advanced analytics, and AI
• Why transactional workloads and reporting/analytics should almost never share the same system
• When to use batch vs. streaming ingestion and how “eventual” really is “good enough” for most reporting
• How AI workloads (training data, RAG, and models) change your storage and processing patterns
• A three-part filter for picking tools: value/ROI, skills & ecosystem, and data gravity & governance
• How to factor in operational overhead, support, and total cost of ownership—not just license price
• How to use the OODA loop (Observe–Orient–Decide–Act) to iterate on architecture
⏱️ Chapters
00:00 The data paradox: tool sprawl, process chaos, and misused tech
03:32 Strategy vs. tactics: starting with goals, not tools
05:38 Process, Platform, People
06:25 From data platforms to workload solutions (problem-first thinking)
08:15 Workload Pillar 1: OLTP
13:29 Workload Pillar 2: Advanced analytics
12:20 Workload Pillar 3: AI
14:45 Filter #1: Value profile
16:23 Filter #2: Skill & maturity
16:38 Filter #3: Gravity & ecosystem
19:00 The OODA loop (Observe–Orient–Decide–Act) & final guidance
đź”— Links
• Explore more Live! 360 sessions: https://aka.ms/L360Orlando25
• Join us at out upcoming VS Live! events: https://aka.ms/VSLiveEvents
👤 Speaker: Buck Woody
Chief Data Officer, Straight Path Solutions
#dataarchitecture #dataengineering #AI
Rust has been named Stack Overflow's Most Loved (now called Most Admired) language every year since our 1.0 release in 2015. That means people who use Rust want to keep using Rust1--and not just for performance-heavy stuff or embedded development, but for shell scripts, web apps, and all kinds of things you wouldn't expect. One of our participants captured it well when they said, "At this point, I don't want to write code in any other language but Rust."
When we sat down to crunch the vision doc data, one of the things we really wanted to explain was: What is it that inspires that strong loyalty to Rust?2 Based on the interviews, the answer is at once simple and complicated. The short version is that Rust empowers them to write reliable and efficient software. If that sounds familiar, it should: it's the slogan that we have right there on our web page. The more interesting question is how that empowerment comes about, and what it implies for how we evolve Rust.
The first thing we noticed is that, throughout every conversation, no matter whether someone is writing their first Rust program or has been using it for years, no matter whether they're building massive data clusters or embedded devices or just messing around, there are a consistent set of things that they say they like about Rust.
The first is reliability. People love that "if it compiles, it works" feeling:
"What I really love about Rust is that if it compiles it usually runs. That is fantastic, and that is something that I'm not used to in Java." -- Senior software engineer working in automotive embedded systems
"Rust is one of those languages that has just got your back. You will have a lot more sleep and you actually have to be less clever." -- Rust consultant and open source framework developer
Another, of course, is efficiency. This comes up in particular at the extremes, both very large scale (data centers) and very small scale (embedded):
"I want to keep the machine resources there for the [main] computation. Not stealing resources for a watchdog." -- Software engineer working on data science platforms
"You also get a speed benefit from using Rust. For example, [..] just the fact that we changed from this Python component to a Rust component gave us a 100fold speed increase." -- Rust developer at a medical device startup
Efficiency comes up particularly often when talking to customers running "at-scale" workloads, where even small performance wins can translate into big cost savings:
"We have a library -- effectively it's like an embedded database -- that we deploy on lots of machines. It was written in Java and we recently rewrote it from Java to Rust and we got close to I think 9x to 10x performance wins." -- Distinguished engineer working on cloud infrastructure services
"I'm seeing 4x efficiency in the same module between Java code that loads a VM and Rust. That's a lot of money you save in data center cost." -- Backend engineering company founder specializing in financial services
At the other end of the spectrum, people doing embedded development or working at low-levels of abstraction highlight Rust's ability to give low-level control and access to system details:
"Rust was that replacement for C I'd been looking for forever." -- Backend engineering company founder specializing in financial services
"If you're going to write something new and you do kind of low-level systemsy stuff, I think Rust is honestly the only real choice." -- Distinguished engineer
Many people cite the importance of Rust's supportive tooling, which helps them get up and going quickly, and in particular the compiler's error messages:
"I think a big part of why I was able to succeed at learning Rust is the tooling. For me, getting started with Rust, the language was challenging, but the tooling was incredibly easy." -- Executive at a developer tools company
"The tooling really works for me and works for us. The number one way that I think I engage with Rust is through its tooling ecosystem. I build my code through Cargo. I test it through Cargo. We rely on Clippy for everything." -- Embedded systems engineer working on safety-critical robotics
"I think the error messages and suggestions from the Rust compiler are super helpful also." -- Professor specializing in formal verification
Finally, one of Rust's most important virtues is its extensibility. Both in the language itself and through the crates.io ecosystem, Rust is designed to let end-users create libraries and abstractions that meet their needs:
"The crate ecosystem combined with the stability guarantees and the semantic versioning mean that it's the best grab and go ecosystem I've ever seen." -- Computer science professor and programming language designer
"I think proc macros are a really big superpower for Rust." -- Creator and maintainer of Rust networking libraries
"Rust is incredibly good at making it very very easy to get started, to reuse things, just to experiment quickly with new tools, new libraries, all the rest of it... so for me, as an experimentation platform, it's great." -- Rust expert and consultant focused on embedded and real-time systems
Reliability, efficiency, tooling, ecosystem—these are all things that people appreciate about Rust. But what they love isn't any one of those things. It's the way the combination makes Rust a trusted, versatile tool that you can bring to virtually any problem:
"When I got to know about it, I was like 'yeah this is the language I've been looking for'. This is the language that will just make me stop thinking about using C and Python. So I just have to use Rust because then I can go as low as possible as high as possible." -- Software engineer and community organizer in Africa
"I wanted a language that works well from top to bottom in a stacking all the way from embedded to very fancy applications" -- Computer science professor and programming language designer
"If [Rust] is going to try and sort of sell itself more in any particular way, I would probably be saying high performance, highly expressive, general purpose language, with the great aspect that you can write everything from the top to the bottom of your stack in it." -- Rust expert and consultant focused on embedded and real-time systems
Take away the reliability, and you don't trust it: you're second-guessing every deployment, afraid to refactor, hesitant to let junior developers touch the critical paths.
"Rust just lowers that bar. It's a lot easier to write correct Rust code. As a leader on the team, I feel a lot safer when we have less experienced engineers contributing to these critical applications." -- Distinguished engineer working on cloud infrastructure services
"My experience with writing Rust software tends to be once you've got it working, it stays working. That's a combination of a lot of care taken in terms of backwards compatibility with the language and a lot of care taken around the general ecosystem." -- Rust expert and consultant focused on embedded and real-time systems
Reliability also provides guardrails that help people enter new domains—whether you're a beginner learning the ropes or an expert venturing into unfamiliar territory:
"Rust introduces you to all these things, like match and all these really nice functional programming methods." -- Software engineer with production Rust experience
"I think Rust ownership discipline is useful both for regular Rust programmers and also for verification. I think it allows you to within the scope of your function to know very clearly what you're modifying, what's not being modified, what's aliased and what's not aliased." -- Professor specializing in formal verification
"I discovered Rust... and was basically using it just to give myself a little bit more confidence being like a solo firmware developer" -- Software engineer working on automotive digital cockpit systems
Take away the efficiency and low-level control, and there are places you can't go: embedded systems, real-time applications, anywhere that cost-per-cycle matters.
"The performance in Rust is nutty. It is so much better and it's safe. When we rewrote C++ and C libraries or C applications into Rust, they would end up being faster because Rust was better at laying out memory." -- Senior Principal Engineer leading consumer shopping experiences
"9 times out of 10, I write microcontroller code and I only test it through unit testing. I put it on real hardware and it just works the first time." -- Embedded systems engineer working on safety-critical robotics
"I can confidently build systems that scale." -- Engineering manager with 20 years experience in media and streaming platforms
Take away the tooling and ecosystem, and you can't get started: or you can, but it's a slog, and you never feel productive.
"For me, getting started with Rust, the language was challenging, but the tooling was incredibly easy... I could just start writing code and it would build and run, and that to me made a huge difference." -- Founder and CEO of company creating developer tools
"Cargo is an amazing package manager. It is probably the best one I've ever worked with. I don't think I ever run into issues with Cargo. It just works." -- Software engineer with production Rust experience
"The Rust compiler is fantastic at kind of the errors it gives you. It's tremendously helpful in the type of errors it produces for it. But not just errors, but the fact it also catches the errors that other languages may not catch." -- Distinguished engineer working on cloud infrastructure services
When all these pieces come together, something interesting happens: Rust becomes a gateway into domains that would otherwise be inaccessible. We heard story after story of people whose careers changed because Rust gave them confidence to tackle things they couldn't before:
"I was civil engineering and I studied front-end development on my own, self taught. I had no computer background. I got interested in Rust and distributed systems and designs and systems around it. I changed my major, I studied CS and Rust at the same time." -- Software engineer transitioning to cryptography research
"I've been working with arbitrary subsidiaries of [a multinational engineering and technology company] for the last 25 years. Always doing software development mostly in the Java space... two years ago I started peeking into the automotive sector. In that context it was a natural consequence to either start working with C++ (which I did not want to do) or take the opportunity to dive into the newly established Rust ecosystem." -- Senior software engineer working in automotive embedded systems
"I started in blockchain. Currently I'm doing something else at my day job. Rust actually gave me the way to get into that domain." -- Rust developer and aerospace community leader
"Before that, I had 10 years of programming on some dynamic programming languages, especially Ruby, to develop web applications. I wanted to choose some language which focuses on system programming, so I chose Rust as my new choice. It is a change of my career." -- Rust consultant and author working in automotive systems and blockchain infrastructure
Each of Rust's attributes are necessary for versatility across domains. But when taken too far, or when other attributes are missing, they can become an obstacle.
One of the most powerful aspects of Rust is the way that its type system allows modeling aspects of the application domain. This prevents bugs and also makes it easier for noobs to get started3:
"Instead of using just a raw bit field, somebody encoded it into the type system. So when you'd have a function like 'open door', you can't pass an 'open door' if the door's already open. The type system will just kick that out and reject it." -- Software engineer working on automotive digital cockpit systems
"You can create contracts. For example, when you are allowed to use locks in which order." -- Senior embedded systems engineer working on automotive middleware development
The problem though is that sometimes the work to encode those invariants in types can create something that feels more complex than the problem itself:
"When you got Rust that's both async and generic and has lifetimes, then those types become so complicated that you basically have to be some sort of Rust god in order to even understand this code or be able to do it." -- Software engineer with production Rust experience
"Instead of spaghetti code, you have spaghetti typing" -- Platform architect at automotive semiconductor company
"I find it more opaque, harder to get my head around it. The types describe not just the interface of the thing but also the lifetime and how you are accessing it, whether it's on the stack or the heap, there's a lot of stuff packed into them." -- Software engineer working on data science platforms
This leads some to advocate for not using some of Rust's more complex features unless they are truly needed:
"My argument is that the hard parts of Rust -- traits, lifetimes, etc -- are not actually fundamental for being productive. There's a way to set up the learning curve and libraries to onboard people a lot faster." -- Creator and maintainer of Rust networking libraries
Async Rust has fueled a huge jump in using Rust to build network systems. But many commenters talked about the sense that "async Rust" was something altogether more difficult than sync Rust:
"I feel like there's a ramp in learning and then there's a jump and then there's async over here. And so the goal is to get enough excitement about Rust to where you can jump the chasm of sadness and land on the async Rust side." -- Software engineer working on automotive digital cockpit systems
"My general impression is actually pretty negative. It feels unbaked... there is a lot of arcane knowledge that you need in order to use it effectively, like Pin---like I could not tell you how Pin works, right?" -- Research software engineer with Rust expertise
For Rust to provide that "trusted tool that will help you tackle new domains" experience, people need to be leverage their expectations and knowledge of Rust in that new domain. With async, not only are there missing language features (e.g., async fn in traits only became available last year, and still have gaps), but the supportive tooling and ecosystem that users count on to "bridge the gap" elsewhere works less well:
"I was in favor of not using async, because the error messages were so hard to deal with." -- Desktop application developer
"The fact that there are still plenty of situations where you go that library looks useful, I want to use that library and then that immediately locks you into one of tokio-rs or one of the other runtimes, and you're like that's a bit disappointing because I was trying to write a library as well and now I'm locked into a runtime." -- Safety systems engineer working on functional safety for Linux
"We generally use Rust for services, and we use async a lot because a lot of libraries to interact with databases and other things are async. The times when we've had problems with this is like, um, unexplained high CPU usage, for example. The only really direct way to try to troubleshoot that or diagnose it is like, OK, I'm going to attach GDB and I'm gonna try to see what all of the threads are doing. GDB is -- I mean, this is not Rust's fault obviously -- but GDB is not a very easy to use tool, especially in a larger application. [..] And with async, it's, more difficult, because you don't see your code running, it's actually just sitting on the heap right now. Early on, I didn't actually realize that that was the case." -- Experienced Rust developer at a company using Rust and Python
Async is important enough that it merits a deep dive. Our research revealed a lot of frustration but we didn't go deep enough to give more specific insights. This would be a good task to be undertaken by the future User Research team (as proposed in our first post).
We mentioned earlier how Rust's extensibility is part of how it achieves versatility. Mechanisms like overloadable operators, traits, and macros let libraries create rich experiences for developers; a minimal standard library combined with easy package management encourage the creation of a rich ecosystem of crates covering needs both common and niche. However, particularly when people are first getting started, that extensibility can come at the cost of supportiveness, when the "tyranny of choice" becomes overwhelming:
"The crates to use are sort of undiscoverable. There's a layer of tacit knowledge about what crates to use for specific things that you kind of gather through experience and through difficulty. Everyone's doing all of their research." -- Web developer and conference speaker working on developer frameworks
"Crates.io gives you some of the metadata that you need to make those decisions, but it's not like a one stop shop, right? It's not like you go to crates.io and ask 'what I want to accomplish X, what library do I use'---it doesn't just answer that." -- Research software engineer
The Rust org has historically been reluctant to "bless" particular crates in the ecosystem. But the reality is that some crates are omnipresent. This is particular challenging for new users to navigate:
"The tutorial uses
Result<Box<dyn Error>>-- but nobody else does. Everybody uses anyhow-result... I started off using the result thing but all the information I found has example code using anyhow. It was a bit of a mismatch and I didn't know what I should do." -- Software engineer working on data science platforms
"There is no clear recorded consensus on which 3P crates to use. [..] Sometimes it's really not clear---which CBOR crate do you use?[..] It's not easy to see which crates are still actively maintained. [..] The fact that there are so many crates on crates.io makes that a little bit of a risk." -- Rust team from a large technology company
We recommend creating an RFC that defines the goals we are shooting for as we work on Rust. The RFC should cover the experience of using Rust in total (language, tools, and libraries). This RFC could be authored by the proposed User Research team, though it's not clear who should accept it — perhaps the User Research team itself, or perhaps the leadership council.
This post identified how the real "empowering magic" of Rust arises from achieving a number of different attributes all at once -- reliability, efficiency, low-level control, supportiveness, and so forth. It would be valuable to have a canonical list of those values that we could collectively refer to as a community and that we could use when evaluating RFCs or other proposed designs.
There have been a number of prior approaches at this work that we could build on (e.g., this post from Tyler Mandry, the Rustacean Principles, or the Rust Design Axioms). One insight from our research is that we don't need to define which values are "most important". We've seen that for Rust to truly work, it must achieve all the factors at once. Instead of ranking, it may help to describe how it feels when you:
This "goldilocks" framing helps people recognize where they are and course-correct, without creating false hierarchies.
We recommend doubling down on extensibility as a core strategy. Rust's extensibility — traits, macros, operator overloading — has been key to its versatility. But that extensibility is currently concentrated in certain areas: the type system and early-stage proc macros. We should expand it to cover supportive interfaces (better diagnostics and guidance from crates) and compilation workflow (letting crates integrate at more stages of the build process).
Rust's extensibility is a big part of how Rust achieves versatility, and that versatility is a big part of what people love about Rust. Leveraging mechanisms like proc macros, the trait system, and the borrow checker, Rust crates are able to expose high-level, elegant interfaces that compile down to efficiemt machine code. At its best, it can feel a bit like magic.
Unfortunately, while Rust gives crates good tools for building safe, efficient abstractions, we don't provide tools to enable supportive ones. Within builtin Rust language concepts, we have worked hard to create effective error messages that help steer users to success; we ship the compiler with lints that catch common mistakes or enforce important conventions. But crates benefit from none of this. RFCs like RFC #3368, which introduced the diagnostic namespace and #[diagnostic::on_unimplemented], Rust has already begun moving in this direction. We should continue and look for opportunities to go further, particularly for proc-macros which often create DSL-like interfaces.
The other major challenge for extensibility is concerned with the build system and backend. Rust's current extensibility mechanisms (e.g., build.rs, proc-macros) are focused on the early stages of the compilation process. But many extensions to Rust, ranging from interop to theorem proving to GPU programming to distributed systems, would benefit from being able to integrate into other stages of the compilation process. The Stable MIR project and the build-std project goal are two examples of this sort of work.
Doubling down on extensibility will not only make current Rust easier to use, it will enable and support Rust's use in new domains. Safety Critical applications in particular require a host of custom lints and tooling to support the associated standards. Compiler extensibility allows Rust to support those niche needs in a more general way.
We recommend finding ways to help users navigate the crates.io ecosystem. Idiomatic Rust today relies on custom crates for everything from error-handling to async runtimes. Leaning on the ecosystem helps Rust to scale to more domains and allows for innovative new approaches to be discovered. But finding which crates to use presents a real obstacle when people are getting started. The Rust org maintains a carefully neutral stance, which is good, but also means that people don't have anywhere to go for advice on a good "starter set" crates.
The right solution here is not obvious. Expanding the standard library could cut off further experimentation; "blessing" crates carries risks of politics. But just because the right solution is difficult doesn't mean we should ignore the problem. Rust has a history of exploring creative solutions to old tradeoffs, and we should turn that energy to this problem as well.
Part of the solution is enabling better interop between libraries. This could come in the form of adding key interop traits (particularly for async) or by blessing standard building blocks (e.g., the http crate, which provides type definitions for HTTP libraries). Changes to coherence rules can also help, as the current rules do not permit a new interop trait to be introduced in the ecosystem and incrementally adopted.
To sum up the main points in this post:
In 2025, 72% of Rust users said they wanted to keep using it. In the past, Rust had a way higher score than any other language, but this year, Gleam came awfully close, with 70%! Good for them! Gleam looks awesome--and hey, good choice on the fn keyword. ;) ↩
And, uh, how can we be sure not to mess it up? ↩
...for experienced devs operating on less sleep, who do tend to act a lot like noobs. ↩
As much as folks are lamenting about the new cloud version of Oracle support, I have other issues on my mind- like trying to acclimate to my first electric vehicle, even though I already owned a gas-powered Mini Cooper.
As I was looking for a good use case to test new vector search with Oracle 26ai, it occurred to me that I could use something better than a key word search when using the manual to my new car.
What if I used the manual, which is public information and could be easily made searchable as my use case?
Imagine you run a support portal (internal or customer-facing) with lots of short “support notes”:
You discover quickly that keyword search often fails because people describe the same problem in different words. Vector search solves this by comparing meaning, not exact terms. I’ve been facing something similar as I try to come up to speed with my car, so I decided to see if AI could help me out.
So in this blog post, I will work on:
Oracle 26ai is a strong fit because it lets you do this inside the database with a native VECTOR type, SQL functions, and built-in vector indexing options.
Assumptions
Dimension note: pick a dimension that matches your embedding model (e.g., 768, 1024, 1536, etc.).
Table to store notes and vectors
1) Drop & create a table for support notes + embeddings
begin
execute immediate 'drop table support_notes purge';
exception
when others then
if sqlcode != -942 then raise; end if;
end;
/
create table support_notes (
note_id number generated by default as identity primary key,
created_at timestamp default systimestamp not null,
title varchar2(200) not null,
body clob not null,
-- VECTOR(d) is the native vector datatype (d = embedding dimension)
embedding vector(1536) not null
);
Oracle’s native VECTOR datatype is designed for storing embeddings directly in tables, so this was surprisingly easy.
Below I show the “shape” of the insert. Replace the […] with real embedding values from your model pipeline.
Make sure to insert precomputed embeddings (example shape; replace with real vectors) when using this yourself:
insert into support_notes (title, body, embedding) values (
'Fast charging fails at public station',
'CCS fast charger starts then stops after 5-10 seconds. Happens on multiple stations.',
vector('[0.0123, -0.0456, 0.0789, ...]') -- 1536 floats
);
insert into support_notes (title, body, embedding) values (
'Charging error after software update',
'After an OTA update, the car reports a charging error intermittently, especially on Level 2.',
vector('[0.0011, -0.0234, 0.0567, ...]')
);
commit;
Oracle 26ai supports generating embeddings via DBMS_VECTOR.UTL_TO_EMBEDDING (using JSON params and an in-database model you’ve loaded).
This Assumes you already loaded an ONNX embedding model named ‘doc_model’.
var params clob;
exec :params := '{"provider":"database","model":"doc_model"}';
insert into support_notes (title, body, embedding)
values (
'EV plug latch stuck',
'The charging connector latch won’t release unless I unlock twice.',
dbms_vector.utl_to_embedding('The charging connector latch won’t release unless I unlock twice.', json(:params))
);
commit;
For fast similarity search, create an HNSW index, i.e. we’ll create an HNSW vector index (in-memory neighbor graph):
create vector index support_notes_hnsw_idx
on support_notes (embedding)
organization inmemory neighbor graph
distance cosine
with target accuracy 90;
I discovered how to do this pattern for HNSW vector indexes in Oracle AI Vector Search in the following blog.
You provide a query vector and ask for the nearest neighbors by cosine distance. The following query will find the five most similar notes in the manual as part of an input vector. We’ll need to replace the :qvec with query embedding(VECTOR(1536)) and in a lot of apps, you can just compute this embedding in the app tier and then bind it.
select
note_id,
title,
vector_distance(embedding, :qvec, cosine) as dist
from support_notes
order by dist
fetch first 5 rows only;
VECTOR_DISTANCE is one of the core vector SQL functions used for similarity search, so it makes this easy, too.
Below is a single, run-it-in-SQLcl demo script for Oracle Database 26ai that does hybrid search (keyword + vector) over a realistic “2024 MINI Cooper SE user manual” use case.
-- mini_manual_hybrid_demo.sql
-- Hybrid search demo for Oracle 26ai: Oracle Text + Vector Search (COSINE, 1536 dims)
-- Use case: Chunked 2024 MINI Cooper SE manual content (simplify manual navigation)
set echo on
set feedback on
set pagesize 200
set linesize 200
set serveroutput on
whenever sqlerror exit sql.sqlcode
prompt =========================================================
prompt 0) Preconditions
prompt - You need an embedding model accessible to DBMS_VECTOR
prompt - Update the PARAMS JSON below to match environment
prompt =========================================================
--------------------------------------------------------------------------------
-- 1) Drop old objects (safe rerun)
--------------------------------------------------------------------------------
begin
execute immediate 'drop table mini_manual_chunks purge';
exception when others then
if sqlcode != -942 then raise; end if;
end;
/
begin
execute immediate 'drop sequence mini_chunk_src_seq';
exception when others then
if sqlcode != -2289 then raise; end if;
end;
/
--------------------------------------------------------------------------------
-- 2) Create table: manual chunks + metadata + embedding
--------------------------------------------------------------------------------
prompt =========================================================
prompt 1) Create storage table for chunked manual text + vectors
prompt =========================================================
create table mini_manual_chunks (
chunk_id number generated by default as identity primary key,
source_id number not null,
doc_title varchar2(200) not null,
section_path varchar2(500) not null, -- e.g. "Charging > troubleshooting"
page_hint varchar2(50),
chunk_text clob not null,
-- dimension is fixed at 1536 (match your embedding model)
embedding vector(1536) not null,
created_at timestamp default systimestamp not null
);
create sequence mini_chunk_src_seq start with 1000 increment by 1;
--------------------------------------------------------------------------------
-- 3) Helper: embedding params + convenience procedure to insert chunks
--------------------------------------------------------------------------------
prompt =========================================================
prompt 2) Setup embedding params + insert helper
prompt =========================================================
-- IMPORTANT: Update this JSON for environment.
-- - {"provider":"database","model":"MINI_MANUAL_EMBED_1536"}
-- - {"provider":"oci","credential_name":"OCI_CRED","endpoint":"...","model":"..."}
-- - {"provider":"openai","credential_name":"...","model":"text-embedding-3-large"}
--
-- Keep the dimension consistent with VECTOR(1536).
var EMBED_PARAMS clob
begin
:EMBED_PARAMS := '{
"provider": "database",
"model": "MINI_MANUAL_EMBED_1536"
}';
end;
/
create or replace procedure add_manual_chunk(
p_source_id in number,
p_doc_title in varchar2,
p_section_path in varchar2,
p_page_hint in varchar2,
p_chunk_text in clob
) as
v_emb vector(1536);
begin
-- Generate embedding in-database
v_emb := dbms_vector.utl_to_embedding(
p_chunk_text,
json(:EMBED_PARAMS)
);
insert into mini_manual_chunks(source_id, doc_title, section_path, page_hint, chunk_text, embedding)
values (p_source_id, p_doc_title, p_section_path, p_page_hint, p_chunk_text, v_emb);
end;
/
show errors
--------------------------------------------------------------------------------
-- 4) Insert realistic sample manual chunks (MINI Cooper SE focused)
-- The ones I chose are short, “chunkable” blocks like you'd create after parsing the PDF.
--------------------------------------------------------------------------------
prompt =========================================================
prompt 3) Insert realistic MINI Cooper SE manual-style sample chunks
prompt =========================================================
declare
v_src number := mini_chunk_src_seq.nextval;
begin
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual'
'Charging > Overview',
'p. 110',
q'[
Charging your vehicle: You can charge using AC charging (Level 1/Level 2) or DC fast charging when equipped and when supported by the charging station.
Always follow the instructions on the charging station and ensure the connector is fully seated before leaving the vehicle.
If charging does not start, verify the vehicle is unlocked (if required), the connector is latched, and the station is authorized.
]'
);
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual',
'Charging > AC charging > Tips',
'p. 114',
q'[
AC charging: Use a compatible charging cable and confirm the outlet or EVSE is operating properly.
If the charging cable has status indicators, check for fault lights. Avoid using extension cords unless explicitly permitted by the EVSE manufacturer.
Charging may be reduced or interrupted to protect the battery under extreme temperatures.
]'
);
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual',
'Charging > DC fast charging > Troubleshooting',
'p. 120',
q'[
DC fast charging: If the charging session starts and then stops, try re-initiating the session and confirm the connector is fully engaged.
Some stations require re-authorization if the session is interrupted.
If repeated attempts fail, try a different stall or station. Inspect the connector for debris and ensure the charge port area is clear.
]'
);
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual',
'Charging > Charge port & connector',
'p. 112',
q'[
Charge port: Keep the charge port and connector clean and dry. Do not insert objects into the charge port.
If the connector does not release, confirm the vehicle is unlocked and follow the recommended release procedure.
Do not force the connector; damage may occur.
]'
);
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual',
'Driver assistance > Lighting > Headlights',
'p. 68',
q'[
Automatic headlight control: When set to the default position, the vehicle controls exterior lights based on ambient light conditions.
Daytime running lights may be active during daylight. In low-light conditions, the system turns on headlights and tail lamps automatically.
Driver remains responsible for using appropriate lighting in poor visibility.
]'
);
add_manual_chunk(
v_src,
'2024 MINI Cooper SE Owner''s Manual',
'Infotainment > Mobile app > Charging status',
'p. 142',
q'[
Charging status in the mobile app: The app may show charging state, estimated completion time, and notifications.
If the app shows an error but the vehicle is charging, refresh the status or verify connectivity.
For persistent issues, confirm the vehicle services are active and the phone has network access.
]'
);
commit;
end;
/
prompt Insert complete.
--------------------------------------------------------------------------------
-- 5) Create HYBRID indexes:
-- a) Oracle Text index on chunk_text for keyword search
-- b) Vector index (HNSW) on embedding for semantic search using cosine distance
--------------------------------------------------------------------------------
prompt =========================================================
prompt 4) Create indexes for HYBRID search (Text + Vector)
prompt =========================================================
-- Oracle Text (keyword / BM25-style scoring with CONTAINS)
-- Note: CTXSYS must be installed/configured
create index mini_manual_text_idx
on mini_manual_chunks(chunk_text)
indextype is ctxsys.context;
-- Vector index (HNSW) for cosine similarity
create vector index mini_manual_vec_idx
on mini_manual_chunks(embedding)
organization inmemory neighbor graph
distance cosine
with target accuracy 90;
--------------------------------------------------------------------------------
-- 6) Queries
--------------------------------------------------------------------------------
prompt =========================================================
prompt 5) DEMO: Pure keyword search (Oracle Text)
prompt =========================================================
-- Keyword query example: "connector does not release"
-- Score is available via SCORE(1)
select
chunk_id,
section_path,
page_hint,
score(1) as text_score,
substr(chunk_text, 1, 160) as preview
from mini_manual_chunks
where contains(chunk_text, 'connector AND release', 1) > 0
order by text_score desc
fetch first 5 rows only;
prompt =========================================================
prompt 6) DEMO: Pure vector similarity search (semantic)
prompt =========================================================
-- Create a query embedding from a user question (in-db)
var Q_TEXT clob
var QVEC vector(1536)
begin
:Q_TEXT := 'My fast charging starts then stops after a few seconds. What should I check?';
:QVEC := dbms_vector.utl_to_embedding(:Q_TEXT, json(:EMBED_PARAMS));
end;
/
select
chunk_id,
section_path,
page_hint,
vector_distance(embedding, :QVEC, cosine) as dist,
substr(chunk_text, 1, 160) as preview
from mini_manual_chunks
order by dist
fetch first 5 rows only;
prompt =========================================================
prompt 7) DEMO: HYBRID search (keyword + vector)
prompt =========================================================
-- Hybrid strategy:
-- 1) Use keyword query to enforce topical relevance (CONTAINS)
-- 2) Use vector distance to order by semantic similarity within that set
var KQ varchar2(4000)
begin
:KQ := 'charging AND (fast OR DC OR station)';
end;
/
select
chunk_id,
section_path,
page_hint,
score(1) as text_score,
vector_distance(embedding, :QVEC, cosine) as dist,
substr(chunk_text, 1, 160) as preview
from mini_manual_chunks
where contains(chunk_text, :KQ, 1) > 0
order by dist
fetch first 5 rows only;
prompt =========================================================
prompt 8) DEMO: “Simplify the manual” output (a friendly answer-shaped result)
prompt =========================================================
-- In a real app you’d pass the top chunk(s) to your summarizer / RAG layer.
-- For demo, we return the best chunk as “what to do next”.
select
'Suggested section: ' || section_path || ' (' || page_hint || ')' as suggestion,
chunk_text as recommended_text
from (
select section_path, page_hint, chunk_text,
vector_distance(embedding, :QVEC, cosine) as dist
from mini_manual_chunks
where contains(chunk_text, :KQ, 1) > 0
order by dist
)
fetch first 1 row only;
prompt =========================================================
prompt DONE.
prompt Next step: replace sample chunks with your parsed manual chunks.
prompt =========================================================
It took me a while to get this to work the way I wanted, had to view several examples, push some of the code through AI and I’m still fiddling with it, but it’s a start to making it easier for me to search the manual with simple text vs. keywords.
I’m parsing the manual PDF into chunks (200–800 tokens-ish each), each with:
SQL> select
2 'Suggested section: ' || section_path || ' (' || page_hint || ')' as suggestion,
3 chunk_text as recommended_text
4 from (
5 select section_path, page_hint, chunk_text,
6 vector_distance(embedding, :QVEC, cosine) as dist
7 from mini_manual_chunks
8 where contains(chunk_text, :KQ, 1) > 0
9 order by dist
10 )
11 fetch first 1 row only;
SUGGESTION
Suggested section: Charging > DC fast charging > Troubleshooting (p. 120)
RECOMMENDED_TEXT
DC fast charging: If the charging session starts and then stops, try re-initiating the session and confirm the connector is fully engaged. Some stations require re-authorization if the session is interrupted. If repeated attempts fail, try a different stall or station. Inspect the connector for debris and ensure the charge port area is clear.
I’ll revisit this as I keep coming up to speed with my new car. I really knew my 2015 Mini Cooper JCW all the way down to the bolts and I’d like to understand my new 2024 Mini Cooper SE Resolute as well. I’m hoping this will be a way to speed up that knowledge transfer.
media3-inspector - Extract metadata and frames outside of playback
media3-ui-compose-material3 - Build a basic Material3 Compose Media UI in just a few steps
media3-cast - Automatically handle transitions between Cast and local playbacks
media3-decoder-av1 - Consistent AV1 playback with the rewritten extension decoder based on the dav1d library
We also added caching and memory management improvements to PreloadManager, and provided several new ExoPlayer, Transformer and MediaSession simplifications.
This release also gives you the first experimental access to CompositionPlayer to preview media edits.
Read on to find out more, and as always please check out the full release notes for a comprehensive overview of changes in this release.
The new media3-inspector module combines all utilities to inspect media without playback in one place:
MetadataRetriever to read duration, format and static metadata from a MediaItem.
FrameExtractor to get frames or thumbnails from an item.
MediaExtractorCompat as a direct replacement for the Android platform MediaExtractor class, to get detailed information about samples in the file.
suspend fun extractThumbnail(mediaItem: MediaItem) { FrameExtractor.Builder(context, mediaItem).build().use { val thumbnail = frameExtractor.getThumbnail().await() } }
We are also still working on even more Compose components, like a prebuilt seek bar, a complete out-of-the-box replacement for PlayerView, as well as subtitle and ad integration.
@Composable fun SimplePlayerUI(player: Player, modifier: Modifier = Modifier) { Column(modifier) { ContentFrame(player) // Video surface and shutter logic Row (Modifier.align(Alignment.CenterHorizontally)) { SeekBackButton(player) // Simple controls PlayPauseButton(player) SeekForwardButton(player) } } }
Simple Compose player UI with out-of-the-box elements
When you set up your MediaSession, simply build a CastPlayer around your ExoPlayer and add a MediaRouteButton to your UI and you're done!
// MediaSession setup with CastPlayer val exoPlayer = ExoPlayer.Builder(context).build() val castPlayer = CastPlayer.Builder(context).setLocalPlayer(exoPlayer).build() val session = MediaSession.Builder(context, player) // MediaRouteButton in UI @Composable fun UIWithMediaRouteButton() { MediaRouteButton() }
New CastPlayer integration in Media3 session demo app
As with all extension decoder modules, please note that it requires building from source to bundle the relevant native code correctly. Bundling a decoder provides consistency and format support across all devices, but because it runs the decoding in your process, it's best suited for content you can trust.
Caching support – When defining how far to preload, you can now choose PreloadStatus.specifiedRangeCached(0, 5000) as a target state for preloaded items. This will add the specified range to your cache on disk instead of loading the data to memory. With this, you can provide a much larger range of items for preloading as the ones further away from the current item no longer need to occupy memory. Note that this requires setting a Cache in DefaultPreloadManager.Builder.
Automatic memory management – We also updated our LoadControl interface to better handle the preload case so you are now able to set an explicit upper memory limit for all preloaded items in memory. It's 144 MB by default, and you can configure the limit in DefaultLoadControl.Builder. The DefaultPreloadManager will automatically stop preloading once the limit is reached, and automatically releases memory of lower priority items if required.
Mute and unmute – We already had a setVolume method, but have now added the convenience mute and unmute methods to easily restore the previous volume without keeping track of it yourself.
Stuck player detection – In some rare cases the player can get stuck in a buffering or playing state without making any progress, for example, due to codec issues or misconfigurations. Your users will be annoyed, but you never see these issues in your analytics! To make this more obvious, the player now reports a StuckPlayerException when it detects a stuck state.
Wakelock by default – The wake lock management was previously opt-in, resulting in hard to find edge cases where playback progress can be delayed a lot when running in the background. Now this feature is opt-out, so you don't have to worry about it and can also remove all manual wake lock handling around playback.
Simplified setting for CC button logic – Changing TrackSelectionParameters to say "turn subtitles on/off" was surprisingly hard to get right, so we added a simple boolean selectTextByDefault option for this use case.
Media3 1.9.0 has new functionality to make this a lot simpler – you can now define your media button preferences with a standard player command, requiring no custom command handling at all.
session.setMediaButtonPreferences(listOf(
CommandButton.Builder(CommandButton.ICON_FAST_FORWARD) // choose an icon
.setDisplayName(R.string.skip_forward)
.setPlayerCommand(Player.COMMAND_SEEK_FORWARD) // choose an action
.build()
))Media button preferences with fast forward button
CompositionPlayer is a new component in the Media3 editing APIs designed for real-time preview of media edits. Built upon the familiar Media3 Player interface, CompositionPlayer allows users to see their changes in action before committing to the export process. It uses the same Composition object that you would pass to Transformer for exporting, streamlining the editing workflow by unifying the data model for preview and export.
We encourage you to start using CompositionPlayer and share your feedback, and keep an eye out for forthcoming posts and updates to the documentation for more details.
val speedProvider = object : SpeedProvider { override fun getSpeed(presentationTimeUs: Long): Float { return speed } override fun getNextSpeedChangeTimeUs(timeUs: Long): Long { return C.TIME_UNSET } } EditedMediaItem speedEffectItem = EditedMediaItem.Builder(mediaItem) .setSpeed(speedProvider) .build()
This new approach replaces the previous method of using Effects#createExperimentalSpeedChangingEffects(), which we've deprecated and will remove in a future release.
This is done via a new EditedMediaItemSequence.Builder constructor that accepts a set of track types (e.g., C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO).
To simplify creation, we've added new static convenience methods:
EditedMediaItemSequence.withAudioFrom(List<EditedMediaItem>)
EditedMediaItemSequence.withVideoFrom(List<EditedMediaItem>)
EditedMediaItemSequence.withAudioAndVideoFrom(List<EditedMediaItem>)
We encourage you to migrate to the new constructor or the convenience methods for clearer and more reliable sequence definitions.
Example of creating a video-only sequence:
EditedMediaItemSequence videoOnlySequence =
EditedMediaItemSequence.Builder(setOf(C.TRACK_TYPE_VIDEO))
.addItem(editedMediaItem)
.build()---