MCPcopy Index your code
hub / github.com/commoncrawl/cc-index-table

github.com/commoncrawl/cc-index-table @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
187 symbols 584 edges 25 files 20 documented · 11%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Common Crawl Index Table

Build and process the Common Crawl index table – an index to WARC files in a columnar data format (Apache Parquet).

The index table is built from the Common Crawl URL index files by Apache Spark. It can be queried by SparkSQL, Amazon Athena (built on Presto or Trino), Apache Hive and many other big data frameworks and applications.

This projects provides a comprehensive set of example queries (SQL) and also Java code to fetch and process the WARC records matched by a SQL query.

Build Java tools

Java 11 or upwards are required.

mvn package

Javadocs

The Javadocs are created by mvn javadoc:javadoc. Then open the file target/reports/apidocs/index.html in a browser.

Source Code Formatting

Run mvn spotless:check and mvn spotless:apply, see the Spotless Maven guide. Java formatting rules are defined in eclipse-formatter.xml.

Spark installation

Spark needs to be installed in order to build the table and also (alternatively) for processing. Please refer to the Spark documentation how to install Spark and set up a Spark cluster.

Building and running using Docker

A Dockerfile is provided to compile the project and run the Spark job in a Docker container.

  1. build the Docker image: sh docker build . -t cc-index-table
  2. run the table converter tool, here showing the command-line help (--help): sh docker run --rm -ti cc-index-table --help More details to run the converter are given below.

Note that the Dockerfile defines the conversion tool as entry point. Overriding the entrypoint would allow to inspect the container using an interactive shell:

$> docker run --rm --entrypoint=/bin/bash -ti cc-index-table

spark@9eb71e5f09a6:/app$ java -version
openjdk version "17.0.15" 2025-04-15
OpenJDK Runtime Environment Temurin-17.0.15+6 (build 17.0.15+6)
OpenJDK 64-Bit Server VM Temurin-17.0.15+6 (build 17.0.15+6, mixed mode, sharing)

Or you could directly call the command spark-submit:

docker run --rm --entrypoint=/opt/spark/bin/spark-submit cc-index-table

Python, PySpark, Jupyter Notebooks

Not part of this project. Please have a look at cc-pyspark for examples how to query and process the tabular URL index with Python and PySpark. The project cc-notebooks includes some examples how to gain insights into the Common Crawl data sets using the columnar index.

Conversion of the URL index

A Spark job converts the Common Crawl URL index files (a sharded gzipped index in CDXJ format) into a table in Parquet or ORC format.

> APPJAR=target/cc-index-table-0.3-SNAPSHOT-jar-with-dependencies.jar
> $SPARK_HOME/bin/spark-submit --class org.commoncrawl.spark.CCIndex2Table $APPJAR

CCIndex2Table [options] <inputPathSpec> <outputPath>

Arguments:
  <inputPaths>
        pattern describing paths of input CDX files, e.g.
        s3a://commoncrawl/cc-index/collections/CC-MAIN-2017-43/indexes/cdx-*.gz
  <outputPath>
        output directory

Options:
  -h,--help                     Show this message
     --outputCompression <arg>  data output compression codec: gzip/zlib
                                (default), snappy, lzo, none
     --outputFormat <arg>       data output format: parquet (default), orc
     --partitionBy <arg>        partition data by columns (comma-separated,
                                default: crawl,subset)
     --useNestedSchema          use the schema with nested columns (default:
                                false, use flat schema)

The script convert_url_index.sh runs CCIndex2Table using Spark on Yarn.

Columns are defined and described in the table schema (flat or nested).

Runing the converter in a Docker container

The converter can be run from the Docker container, built from the Dockerfile, see the instructions above.

The steps given below are just an example – the way data is passed in and out from the container may vary.

# create a test folder
mkdir -p /tmp/data/in

# copy CDX files into /tmp/data/in/
cp .../*.cdx.gz /tmp/data/in/

tree /tmp/data/
# outputs:
# /tmp/data/
# └── in
#     └── CC-MAIN-20241208172518-20241208202518-00000.cdx.gz

# ensure that also the user "spark" in the container has write permissions
chmod a+w /tmp/data

# note: the output will be written to /tmp/data/out/, but Spark
#       will complain if the output folder already exists

# launch the Docker container, running the Spark job
docker run --mount=type=bind,source=/tmp/data,destination=/data --rm cc-index-table /data/in /data/out

tree /tmp/data/
# /tmp/data/
# ├── in
# │   └── CC-MAIN-20241208172518-20241208202518-00000.cdx.gz
# └── out
#     ├── crawl=CC-MAIN-2024-51
#     │   └── subset=warc
#     │       └── part-00000-4b2c091d-24db-4248-8c3c-817fd04b7a85.c000.gz.parquet
#     └── _SUCCESS

Query the table in Amazon Athena

First, the table needs to be imported into Amazon Athena. In the Athena Query Editor:

  1. create a database ccindex: CREATE DATABASE ccindex and make sure that it's selected as "DATABASE"
  2. edit the "create table" statement (flat or nested) and add the correct table name and path to the Parquet/ORC data on s3://. Execute the "create table" query.
  3. make Athena recognize the data partitions on s3://: MSCK REPAIR TABLE ccindex (do not forget to adapt the table name). This step needs to be repeated every time new data partitions have been added.

A couple of sample queries are also provided (for the flat schema): - count captures over partitions (crawls and subsets), get a quick overview how many pages are contained in the monthly crawl archives (and are also indexed in the table): count-by-partition.sql - page/host/domain counts per top-level domain: count-by-tld-page-host-domain.sql - "word" count of - host name elements (split host name at . into words): count-hostname-elements.sql - URL path elements (separated by /): count-url-path-elements.sql - count - HTTP status codes: count-fetch-status.sql - the domains of a specific top-level domain: count-domains-of-tld.sql - page captures of Internationalized Domain Names (IDNA): count-idna.sql - URL paths pointing to robots.txt files count-robotstxt-url-paths.sql (note: /robots.txt may be a redirect) - pages of the Alexa top 1 million sites by joining two tables (ccindex and a CSV file): count-domains-alexa-top-1m.sql - compare document MIME types (Content-Type in HTTP response header vs. MIME type detected by Tika: compare-mime-type-http-vs-detected.sql - distribution/histogram of host name lengths: host-length-distrib.sql - export WARC record specs (file, offset, length) for - a single domain: get-records-of-domain.sql - a specific MIME type: get-records-of-mime-type.sql - a specific language (e.g., Icelandic): get-records-for-language.sql - home pages of a given list of domains: get-records-home-pages.sql - find homepages for low-resource languages: get-home-pages-languages.sql - obtain a random sample of URLs: random-sample-urls.sql - find similar domain names by Levenshtein distance (few characters changed): similar-domains.sql - average length, occupied storage and payload truncation of WARC records by MIME type: average-warc-record-length-by-mime-type.sql - count pairs of top-level domain and content language: count-language-tld.sql - find correlations between TLD and content language using the log-likelihood ratio: loglikelihood-language-tld.sql - ... and similar for correlations between content language and character encoding: correlation-language-charset.sql - site discovery by content language: - specific language(s): site-discovery-by-language.sql - non-English sites: discovery-of-non-english-sites - Hungarian sites: site-discovery-hungarian.sql - find multi-lingual domains by analyzing URL paths: get-language-translations-url-path.sql - extract robots.txt records for a list of sites: get-records-robotstxt.sql

Athena creates results in CSV format. E.g., for the last example, the mining of multi-lingual domains we get:

domain n_lang n_pages lang_counts
vatican.va 40 42795 {de=3147, ru=20, be=1, fi=3, pt=4036, bg=11, lt=1, hr=395, fr=5677, hu=79, uc=2, uk=17, sk=20, sl=4, sp=202, sq=5, mk=1, ge=204, sr=2, sv=3, or=2243, sw=5, el=5, mt=2, en=7650, it=10776, es=5360, zh=5, iw=2, cs=12, ar=184, vi=1, th=4, la=1844, pl=658, ro=9, da=2, tr=5, nl=57, po=141}
iubilaeummisericordiae.va 7 2916 {de=445, pt=273, en=454, it=542, fr=422, pl=168, es=612}
osservatoreromano.va 7 1848 {de=284, pt=42, en=738, it=518, pl=62, fr=28, es=176}
cultura.va 3 1646 {en=373, it=1228, es=45}
annusfidei.va 6 833 {de=51, pt=92, en=171, it=273, fr=87, es=159}
pas.va 2 689 {en=468, it=221}
photogallery.va 6 616 {de=90, pt=86, en=107, it=130, fr=83, es=120}
im.va 6 325 {pt=2, en=211, it=106, pl=1, fr=3, es=2}
museivaticani.va 5 266 {de=63, en=54, it=47, fr=37, es=65}
laici.va 4 243 {en=134, it=5, fr=51, es=53}
radiovaticana.va 3 220 {en=5, it=214, fr=1}
casinapioiv.va 2 213 {en=125, it=88}
vaticanstate.va 5 193 {de=25, en=76, it=24, fr=25, es=43}
laityfamilylife.va 5 163 {pt=21, en=60, it=3, fr=78, es=1}
camposanto.va 1 156 {de=156}
synod2018.va 3 113 {en=24, it=67, fr=22}

Process the Table with Spark

Export Views

As a first use case, let's export parts of the table and save it in one of the formats supported by Spark. The tool CCIndexExport runs a Spark job to extract parts of the index table and save it as a table in Parquet, ORC, JSON or CSV. It may even transform the data into an entirely different table. Please refert to the Spark SQL programming guide and the overview of built-in SQL functions for more information.

The tool requires as arguments input and output path, but you also want to pass a useful SQL query instead of the default SELECT * FROM ccindex LIMIT 10. All available command-line options are show when called with --help:

```

$SPARK_HOME/bin/spark-submit --class org.commoncrawl.spark.examples.CCIndexExport $APPJAR --help

CCIndexExport [options]

Arguments: path to cc-index table s3://commoncrawl/cc-index/table/cc-main/warc/ output directory

Options: -h,--help Show this message -q,--query

Core symbols most depended-on inside this repo

getHostName
called by 18
src/main/java/org/commoncrawl/net/WarcUri.java
getString
called by 15
src/main/java/org/commoncrawl/spark/IndexTable.java
getHostName
called by 13
src/main/java/org/commoncrawl/net/HostName.java
getDomainNameUnderRegistrySuffix
called by 10
src/main/java/org/commoncrawl/net/HostName.java
toString
called by 10
src/main/java/org/commoncrawl/net/WarcUri.java
getReverseHost
called by 8
src/main/java/org/commoncrawl/net/HostName.java
are_parquet_file_row_groups_min_max_ordered
called by 8
src/util/are_part_min_max_increasing.py
readJsonSchemaResource
called by 7
src/main/java/org/commoncrawl/spark/IndexTable.java

Shape

Method 142
Class 26
Function 18
Enum 1

Languages

Java90%
Python10%

Modules by API surface

src/main/java/org/commoncrawl/spark/IndexTable.java20 symbols
src/test/java/org/commoncrawl/net/TestURL.java17 symbols
src/main/java/org/commoncrawl/net/HostName.java15 symbols
src/main/java/org/commoncrawl/net/WarcUri.java14 symbols
src/util/test/test_are_part_min_max_increasing.py11 symbols
src/test/java/org/commoncrawl/net/WarcUriTest.java11 symbols
src/test/java/org/commoncrawl/net/HostNameTest.java9 symbols
src/test/java/org/commoncrawl/spark/TestIndexTableBase.java8 symbols
src/main/java/org/commoncrawl/spark/examples/CCIndexExport.java8 symbols
src/main/java/org/commoncrawl/spark/CCIndex2Table.java7 symbols
src/test/java/org/commoncrawl/spark/TestIndexTable.java6 symbols
src/test/java/org/commoncrawl/spark/TestEOTIndexTable.java6 symbols

For agents

$ claude mcp add cc-index-table \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact