Skip to content

Repository files navigation

πŸ”Ž The Crawlers β€” News Search Engine

A full-text news search engine built from scratch in Java β€” no Lucene, no Elasticsearch. It crawls thousands of Guardian articles, runs them through a real NLP pipeline, builds a compressed positional inverted index, and answers ranked, Boolean, and phrase queries in milliseconds.

Java Ranking Index NLP Status


Overview

This project implements a complete information-retrieval system β€” crawling, indexing, and ranked retrieval β€” with every stage written by hand rather than delegated to a search library. It was built by Team 5 "The Crawlers" for the Design and Implementation of Search Engines course (Summer Semester 2019) and indexes articles from The Guardian's Open Platform API.

Metric Value
πŸ“° Articles crawled & indexed ~2,800
πŸ”€ Query types ranked free-text Β· Boolean Β· phrase
πŸ† Ranking model Okapi BM25
πŸ—œοΈ Index storage compressed β€” Ξ”-encoding + Variable-Byte + Huffman
🧱 External search libraries none β€” index & ranking built from scratch

Features

  • BM25 ranking β€” results are scored with the Okapi BM25 model (tunable k1, b, k2), the same family of ranking functions used by Lucene and Elasticsearch.
  • Boolean retrieval β€” AND / OR / NOT with parentheses and operator precedence, evaluated with an operator/operand stack (e.g. Merkel NOT Trump, (Trump AND Putin) OR G20).
  • Phrase queries β€” quoted queries like "make America great again" are matched using the positional postings, so word order matters.
  • Positional inverted index β€” stores term β†’ { docId β†’ [positions] }, the foundation for phrase and proximity search.
  • Compressed on-disk index β€” postings are gap-encoded (Ξ”) then Variable-Byte encoded, and the term dictionary is Huffman-coded, so the index stays compact and fast to load.
  • Real NLP normalization β€” tokenization, lower-casing, stop-word removal and Porter stemming (Apache OpenNLP), applied identically to documents and queries so running, runs and ran all match.
  • Keyword-in-context snippets β€” results show the matched terms within their surrounding text.

Index & compression design

The index is split into a dictionary file and a postings file, each compressed with the method best suited to it β€” Huffman for the token strings, Variable-Byte for the numeric byte offsets and gap-encoded posting lists. This keeps decompression fast and parallelizable.

Index compression schema: Huffman-coded dictionary + delta/VByte-encoded postings

Search in action

Ranked results for the phrase query "fridays for future" β€” each hit shows the title, authors, source URL, and keyword-in-context snippets:

Ranked search results with keyword-in-context snippets

Architecture

flowchart LR
    A["The Guardian<br/>Open Platform API"] -->|jsoup + Jackson| B["Crawler"]
    B -->|articles as CSV| C["Text pipeline<br/>tokenize / stopwords / Porter stem"]
    C --> D["Inverted indexer<br/>term to docId to positions"]
    D -->|delta + VByte + Huffman| E[("Compressed index<br/>+ dictionary on disk")]
    Q["User query"] --> C
    C --> R{"Query type"}
    R -->|free text| BM["BM25 ranking"]
    R -->|AND / OR / NOT| BOOL["Boolean retrieval"]
    R -->|quoted| PH["Phrase / positional match"]
    E --> BM & BOOL & PH
    BM & BOOL & PH --> OUT["Ranked results<br/>+ snippets"]
Loading

Tech stack

Concern Technology
Language Java 8+
HTTP / HTML parsing jsoup
JSON parsing Jackson
NLP / stemming Apache OpenNLP (Porter stemmer)
Ranking Okapi BM25 (implemented from scratch)
Compression Ξ”-encoding Β· Variable-Byte Β· Huffman coding (from scratch)
Tests JUnit 5

Getting started

Prerequisites

  • JDK 8+ (the crawler uses javafx.util.Pair, bundled with JDK 8)
  • A free Guardian Open Platform API key β€” only needed to crawl fresh data. Searching the bundled offline corpus works without one.

Configuration

No API key is committed to this repository. To crawl fresh articles, supply your own key via the GUARDIAN_API_KEY environment variable:

# Linux / macOS
export GUARDIAN_API_KEY="your-key-here"

# Windows (PowerShell)
$env:GUARDIAN_API_KEY = "your-key-here"

The code reads it at runtime with System.getenv("GUARDIAN_API_KEY") (see Constants.java).

Run

The repository is an Eclipse/IntelliJ project:

  1. Import it into your IDE and make sure the jars in libs/ are on the build path (referenced by .classpath).
  2. Run Main (de.intsys.krestel.SearchEngine.Main). By default it loads the index and runs a batch of sample queries, then drops into an interactive prompt.
  3. Type a query and press Enter. Try:
    • Trump Putin β€” ranked free-text search
    • Merkel NOT Trump β€” Boolean
    • "fridays for future" β€” phrase search
  4. Type exit to quit.

Prebuilt runnable jars are also included in the repo root (SearchEngine.jar).

Project structure

src/de/intsys/krestel/SearchEngine/
β”œβ”€β”€ Main.java                     # Entry point: load index, run queries
β”œβ”€β”€ SearchEngineTheCrawlers.java  # Crawls The Guardian API; orchestrates index/search
β”œβ”€β”€ Article.java / LightArticle.java   # Article model + text normalization
β”œβ”€β”€ InvertedIndexer.java          # Builds & queries the positional inverted index
β”œβ”€β”€ IdxDico.java                  # Index dictionary (term β†’ byte offset)
β”œβ”€β”€ BooleanRetrieval.java         # AND / OR / NOT query evaluation
β”œβ”€β”€ search/BM25.java              # Okapi BM25 ranking
β”œβ”€β”€ hdt/VByte.java, Mutable.java  # Variable-Byte integer (de)compression
β”œβ”€β”€ kimhuffman/                   # Huffman coding for the term dictionary
β”œβ”€β”€ Constants.java                # Configuration (API key read from env)
└── ArticleTest.java              # JUnit tests
libs/                             # Bundled dependencies (jsoup, Jackson, OpenNLP)
img/ Β· Assignments/               # Screenshots, report figures, course assignments

Team

Built by Team 5 β€” The Crawlers:

  • Mohamed Karim Belaid (@Karim-53)
  • Faizuddin Nasaruddin

About

πŸ”Ž A from-scratch Java news search engine over ~2,800 Guardian articles: BM25 ranking, Boolean & phrase queries, and a compressed positional inverted index (Ξ” + Variable-Byte + Huffman). No Lucene/Elasticsearch.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages