Loading the index is done by way of the main qserv-data-loader.py script, with the "-i"/"--index-db" option flag. The default is for the table to go into the qservMeta database. The main script invokes admin/python/lsst/qserv/admin/dataLoader.py, where the indexDb parameter is used; no secondary index is generated if the oneTable flag is set.
In dataLoader.py, _makeIndex does the work, creating a three-column table with the key (objectId) column name taken from the partition options file "id" entry, and the chunk columns named chunkId and subChunkId, respectively. The latter two are currently INT; should we compress that to SMALLINT (or better, UNSIGNED SMALLINT)?
Finally, there are two functions which actually fill the secondary index: _makeIndexMultiNode for a system with a czar and multiple workers, or _makeIndexSingleNode for a single-host test. Both of these call _loadChunkIndex, which gets the three columns of data for the given chunk on the worker, packs that data into a tab-delimited temp file (in-memory file), then loads it into the secondary index table.
Ran some simple greps to identify places where "get chunk" or "objectId" are referred to in the QServ code. Will consult with John Gates and Fritz Mueller about what I've missed.