I think your should consider that using an API could result in fakes, wrongly-validated data. Using an API means you fully trust the API service,... which is kind-of against bitcoin no-trust model.
I recommend you to run a full node (Bitcoin Core 0.13.2 during time of writing).
There is no address-index (there is a patch you can manually compile into Core).
Simplest way with standard Bitcoin-Core 0.13.2 is to import all your addresses as watch-only into a wallet.
Use the RPC call
importaddress <address> "" false to import a watch only address.
The 3rd argument
false is required to not rescan the blockchain for each import (can take serval hours).
Once you have imported all addresses, stop bitcoind/qt and restart it with the startup argument
The rescan may take a couple of minutes/hours (depending on your Disk/RAM/CPU). Once done, you can call
getreceivedbyaddress <addr> for each address to get the balance.
This result in authentic, self-validated data.
Note: If you are using Bitcoin Core 0.14, consider importing multiple addresses with