Project 2 Science: NanoQuery

Data Science track
CS145: Stanford University, Fall 2026.

What you will build

Build NanoQuery, a small agentic analytics stack for your own dataset. Connect tables to domain documents and answer analytical questions. Higher tiers test whether reusable SQL definitions help an LLM answer questions correctly.

Requirements and resources

Proposal: Oct 30 (10 points; no late days)Final: Nov 20 (up to 90 PTS; late-day policy)

Phase 0: Prepare your data and proposal

  1. Choose your tables: Use either partner’s Project 1 dataset and setup, or a different public dataset meeting the same data requirements.
  2. Add documents: Select 100–200 related Wikipedia articles, or use your own relevant domain documents (document setup), prepare them with Spark, and map them to your table records. Inspect a random sample of 30 documents for relevance (all documents if your custom collection has fewer than 30).
  3. Query and submit: Run one keyword join combining documents and tables, create one chart, and complete the proposal checklist.

Embeddings and LLM runs are not required for the proposal.

After Phase 0: Build NanoQuery

  • Data: Continue with your Phase 0 tables and documents; use the supplied chunker to create passages.
  • Core work: Create embeddings and complete five analytical queries and three charts in total. Your Phase 0 query and chart count toward these totals if they meet the final requirements. Two queries must use semantic retrieval to combine document evidence with tables.
  • Higher tiers: Build a tested SQL library, establish five verified answers, then evaluate text-to-SQL. See Grading.
  • Submit: One executed notebook with saved results and a half-to-one-page writeup. See What to submit.

Resources

Download CS145 NanoQuery Colab (October 16)

In Colab, choose File → Upload notebook. Local Jupyter also works.

Runtime: CPU works; use a GPU if available to speed up embeddings. The notebook selects an available GPU automatically; otherwise it uses CPU.

HTML preview — quick browsing Examples — worked report and topic ideas BigQuery setup and troubleshooting AI policy and Honor Code

Teams: Two students recommended; solo allowed. One submission per team. Late days are deducted from both partners and limited by the smaller remaining balance. See the partnership and late-day policy.

Grading

We grade completed work, with partial credit in each category. Your proposed tier is a planning target, not a score cap.

Read NanoQuery requirements
Figure 1. NanoQuery roadmap. Phase 0 (10 PTS) + core analysis (70 PTS) = T80 (80 total). Add the SQL library (+7 PTS) to reach T87 (87 total). Click a stage for details.
80 · Data preparation, SQL, and visualizationsFive analytical queries, two document/table analyses, three charts, and a writeup.

In the notebook: Phases 0–1 and Sections 1–4.

Each analytical query must combine at least two of joins, CTEs, window functions, subqueries, CASE-based analysis, and semantic retrieval. CASE-based analysis applies a classification or calculation rule used in your answer. Semantic retrieval followed by a join counts as two techniques. Each chart must show a specific query result with a title, labeled axes, and a short caption.

Graded work PTS
Prepare documents, check their links to tables, and submit the proposal (Phase 0) 10
Create passages and embeddings, load BigQuery, and run semantic search (Phase 1) 10
Write five analytical queries and create three visualizations 20
Check document evidence, table mappings, and answers for two of those queries 15
Analyze query cost and estimate I/O at 10× and 100× scale 10
Explain findings (5 PTS), AI use and checks (6 PTS), and the pipeline (4 PTS) 15
Core total 80

Section 4 writeup: Half a page to one page. Code, figures, tables, and Section 7 evaluation are outside this limit. Include 2–3 examples of AI assistance and how you checked its suggestions. If you did not use AI assistance, describe 2–3 independent checks, debugging decisions, or revisions instead. Tier 100 still requires the LLM experiment.

Document and table checks (15 points)

Reuse two of your five analytical queries. For each, show the question, retrieved excerpts and source links or paths, mapping to table IDs, SQL, and checked result.

87 · Governed SQL library (+7 PTS)Add five tested definitions with domain rules and SQL templates.

In the notebook: Section 5 — Governed SQL library.

Reuse your five analytical queries. Turn each into a named, parameterized SQL definition with clear domain rules and a small correctness test. At T100, these definitions provide context for the LLM.

93 · Ground truth (+6 PTS)Apply your SQL library to new questions and establish an answer key.

In the notebook: Section 6 — Ground truth.

Save your T87 SQL library, then choose five new questions that reuse or combine its definitions. Change parameters, filters, or aggregations rather than repeating the original questions. Reuse your existing tables and documents.

Build a verified answer key for T100; no LLM run is required for T93. Setup and test queries do not count toward the five analytical or five reference queries.

100 · Text-to-SQL comparison (+7 PTS)Test whether library context helps an LLM answer your five verified questions.

In the notebook: Section 7 — Text-to-SQL comparison and evaluation.

For the same five questions, generate SQL with two prompts:

Keep the saved T87 SQL library fixed across all five comparisons. Keep the Tier 93 reference SQL and results out of both prompts. For each question, keep the model, settings, data, and question-specific instructions identical. For document-based questions, give both prompts the same entity IDs used in the T93 reference.

Use the notebook helper to build the prompts. Paste each into a fresh chat, then paste the original SQL response back into the notebook.

Which tables can the generated SQL use?

List the allowed project.dataset.table IDs, including document tables. Check every physical table in joins, CTE bodies, and subqueries. CTE names and aliases are not additional physical tables. Reject unapproved, unsupported, or unresolved references; do not silently extend the list.

Show one allowed query and one rejected query. On rejection, save the original SQL and reason, skip execution, and continue. These checks belong to the 2 PTS for safe execution.

Different SQL can produce the same correct answer. Full credit is possible at any model accuracy when your references, checks, and analysis are correct. Preserve original responses; label later fixes and reruns separately. Five questions support a case study, not a general claim about model accuracy.

Bonus: Staff select the top five Science projects for overall quality and compelling work; each receives 0–5 bonus points.

Vector indexes and hybrid retrieval are optional experiments.

Getting started: tables and documents

Why Wikipedia? Wikipedia provides background facts that your tables may not contain.

  1. Choose related documents: select 100–200 Wikipedia articles that support questions about your tables, or use your own relevant domain documents.
  2. Prepare the documents: for Wikipedia, enter titles in TITLES and run the download cells. For custom documents, supply an extract with id, url (source link or stable path), title, and text. Run the Spark preparation cells and inspect a random sample of 30 documents for relevance (all if fewer than 30). Replace missing or unrelated documents.
  3. Connect documents to tables: map document facts to table IDs using names, locations, identifiers, or other evidence. Keep source links or paths and the evidence for each match; report missing or ambiguous matches. You may map manually; for large mappings, use an automated check and a reproducible manual sample. The 30-document sample checks relevance, not mapping correctness.

Example: waterfront-park article → park location → taxi-zone ID → compare weekend and weekday drop-offs.

For categories, write a labeling rule and check the assigned labels. Documents must affect the records selected or the information returned in your two document/table analyses. See T80 for scoring and evidence requirements.

Optional: use AI to suggest articles

“My dataset contains [tables and columns]. I want to answer [example questions]. Suggest Wikipedia articles that provide useful facts or background. Group them by topic and explain the connections.”

Review the suggestions and download the original articles; do not treat generated summaries as source documents.

Report document count, passage count, text bytes, and embedding dimensions.

Suggested schedule

Only the proposal and final submission are deadlines; adjust this suggested pace to your target tier.

AI policy and Honor Code

Use AI as a consultant. Draft your analytical queries, SQL definitions, and implementation yourself first. Then use AI to brainstorm, explain, or debug. Compare its suggestions with your draft, test the changes, and write your final code yourself. Explain each query and design choice with the chat window closed.

Source selection: AI may suggest article titles. Review the suggestions and use the original source documents, not generated summaries. Record this assistance.

LLM experiments: Your chosen LLM may generate SQL inside the workflow. Keep those outputs in your experiment records and evaluate them against reference SQL and answers that you wrote and checked.

Use the supplied setup code and model libraries. Generate your own embeddings from the selected text. Precomputed Wikipedia embeddings and pre-built project solutions are prohibited.

Honor Code

Troubleshooting

Getting started

Is it a bug in the starter Colab?

We’ve aimed to keep the project page and notebook consistent. The project page gives the full requirements and grading; the notebook provides compact guidance, function contracts, and starter code.

The supplied helpers support setup and retrieval; you write your dataset-specific queries, mappings, and tests through T87. For T93–T100, extend your work with verified reference answers and the LLM comparison. You may need to adapt the helpers to your implementation.

You’re welcome to adapt the starter code within the project requirements. If something seems inconsistent or buggy, check the project page and ask privately on Ed; include the error and a small reproducible example for bugs. Note important assumptions in your notebook so we can take them into account when reviewing your work.

What is supplied, and what do we write?

The starter supplies setup, chunking, BigQuery helpers, A/B prompts, read-only SQL checks, query-byte limits, and response capture. You write filters, mappings, analytical SQL, and the table allowlist check, plus tests and evaluation for your tier. No frontend or model training is required.

Setup and resources

What should setup confirm before I start?

Use your own Google Cloud project ID, choose a dataset for your project outputs, and match its location to your source data. Enable RUN_BIGQUERY and run the connection check. It checks SELECT 1, reads one row from your chosen source table, and loads and reads a tiny setup table in your output dataset. For Wikipedia, fill in the article titles and contact field, then enable RUN_COLLECTION. For custom documents, follow the document setup instructions. Keep the large source tables in BigQuery.

What does MAX_BYTES_BILLED mean?

The starter’s 100 MB default limits each query’s estimated scan, not your total dataset size. Call preview_query(sql) to see the estimate and limit before execution. If the estimate exceeds the limit, narrow the scan or deliberately change the limit within your available quota. The notebook never raises it automatically. A LIMIT clause restricts returned rows and generally does not reduce the bytes scanned.

Where should I run the project?

Tables stay in BigQuery; Spark and MiniLM run in Colab or locally. For local work, use Python 3.11+, Java 17, Google Application Default Credentials, and preferably at least 8 GB RAM. In Colab, uncomment the notebook’s optional Drive checkpoint cell before collecting documents; rerun it after reconnecting to reuse saved files. Saving the notebook alone does not preserve runtime files; runtime availability varies.

Which models can I use?

The starter loads MiniLM for embeddings. T100 also uses an LLM chat of your choice; follow the T100 comparison instructions.

Do I need BigQuery credits or billing?

Billing is not required. We verified imports, embedding uploads, vector search, and SQL with billing disabled. Stay within BigQuery sandbox limits. Billing for additional experiments is optional and does not change grading.

Data preparation and embeddings

Do we still use Spark?

Use Spark to load, filter, deduplicate, and prepare the extract. Practice building a reproducible preparation step on a small collection. Save Parquet and stop the Spark session before computing embeddings. The starter also releases its local Spark gateway; a kernel restart after checkpointing is another option.

How do we create passages?

Use the supplied chunker on your documents or selected relevant sections. If you select sections, record your selection rule. Preserve document IDs, source links or paths, and passage IDs. The chunker keeps passages within MiniLM's input limit. Use the same MiniLM model for passages and search questions.

Where are the embeddings computed and stored?

Compute them in Colab or local Jupyter with sentence-transformers/all-MiniLM-L6-v2. Save the text, source identifiers, and embedding arrays as Parquet, then batch-load the records into BigQuery. Query embeddings are computed with the same model and passed into SQL. No remote embedding endpoint or vector index is required.

What if semantic search returns an unrelated excerpt?

Inspect the text and the document-to-table mapping. Record the mismatch and refine your question or document selection. Preserve the evidence for your final queries so another reader can check the answers.

Analysis and scale

What counts as an analytical query?

For example, join trips to zones, then use a window function to rank zones by trip count. This combines two required techniques. See the Tier 80 rubric for the full rule.

How do we do scale analysis on a small dataset?

Inspect one analytical query's measured bytes and available execution details. Choose an appropriate operator from the Module 3 lessons, state page size, buffer size, and input cardinalities, and compute I/O at the current size and hypothetical 10× and 100× sizes. State which inputs grow and when the algorithm needs more passes. Apply the textbook algorithm to your stated assumptions and label the results as estimates. Keep this analysis computational; use your existing data.

What to submit

Proposal due Oct 30. Final notebook due Nov 20. Submit through Gradescope.

Proposal · Oct 30

Submit executed Phase 0 cells: the Spark load/filter, document-to-table mapping, one keyword join and chart, and a random sample of 30 documents (all if fewer than 30) labeled for domain relevance, with the fraction relevant reported. Add your target tier, example questions, source details, and partner work split. No late days are allowed for the proposal. Embeddings and LLM runs are not required for the proposal. Your proposal query and chart count toward the final totals if they meet the final requirements.

Final · Nov 20

Examples

These examples suggest a direction. Choose questions your own data and documents can answer.

End-to-end example: Global Fishing Watch

Open the Global Fishing Watch example. A worked flow with queries, code, and saved results.

Optional background

Spark & Distributed SQL colab (~3 min, background)

Optional background: the Spark and Distributed SQL colab walkthrough from Module 5.