Loading many matches using dota2-api

As you remember in the previous post we used a single match loading match_id. Downloading many matches by some criterion is more demanding task. I.e. all games by some player. I will unfortunately upset those who want to download all of its 3000+ games. API allows to get only last 500 matches. It is impossible to avoid this restriction. Let’s see how to get at least that is allowed. Class Dota2Api\Mappers\MatchesMapperWeb exists in the dota2-api for this.

require_once 'vendor/autoload.php';
require_once 'api-key.php';
 
\Dota2Api\Utils\Request::$apiKey = API_KEY;
$mapper = new Dota2Api\Mappers\MatchesMapperWeb();
$mapper->setAccountId(76482434); // Admiral Bulldog
 
/* $var Dota2Api\Models\Match[] */
$matches = $mapper->load();

We get 100 games from 500 needed. How to get last 400? Cap. O. said that loop is needed here. He is right. However an exit condition is needed for a loop i.e. some criterion shows that all matches are already loaded. API returns such fields as total_results and results_remaining in the response. First one shows how many matches are going with the criterion provided. Second one shows how many records left. So, total_results is 500 and results_remaining is 400 for the request used earlier. MatchesMapperWeb has a field called start_at_match_id used to set a shift in the matches result. Mapper has method setStartAtMatchId to set its value.

while ($mapper->getResultsRemaining() != 0) {
    $match = end($matches);
    if (!$match) {
        break;
    }
    $mapper->setStartAtMatchId($match->get('match_id') - 1);
    $newMatches = $mapper->load();
    if (!is_null($newMatches)) {
        $matches = array_merge($matches, $newMatches);
    }
}
echo count($matches)."\n"; // 500
echo $mapper->getResultsRemaining()."\n"; // 0
echo $mapper->getTotalMatches()."\n"; // 500

It’s up to you what to do with the matches received. As for me, it’s better to store them to the local DB to avoid extra API-requests. This data won’t be changed, because matches are already ended. Later we’ll come back to the question about saving matches to the DB. There is more actual problem for now — how to specify the filtration criterion. You can find about 10 parameters described on the page wiki-GetMatchHistory. Unfortunately, most of them doesn’t work.

We start with a game_mode. Providing that we need only CM-matches where AdmiralBulldog have played:

$mapper = new Dota2Api\Mappers\MatchesMapperWeb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setGameMode(2); // CM
$matches = $mapper->load();

API-response is the same as without CM. Maybe AB have played CM only? We can set game_mode equal to -1 (totally invalid) to check if API uses this parameter:

$mapper = new Dota2Api\Mappers\MatchesMapperWeb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setGameMode(-1); // invalid value
$matches = $mapper->load();

API-response is still the same. Next parameter id date_min. It is used to determine minimum date after each match has to be played. It’s pretty good filter, but it doesn’t work as well. To check this we may set future value:

$mapper = new Dota2Api\Mappers\MatchesMapperWeb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setDateMin(strtotime('+1 week')); // Back to the Future
$matches = $mapper->load();

We set data equal to the next week in the example above. The result hasn’t changed. It is equal to the 500 matches and current response contains 100 latest matches.

Moving to leagueid. It allows to filter matches that were played in some tournament. Let’s check The International 2016 (there are only qualifiers played for the moment). The Alliance team (AB is member of this team)has played 18 matches there. Let’s see which result will API return if we set leagueid equal to 4664 (TI6 identifier):

$mapper = new Dota2Api\Mappers\MatchesMapperWeb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setLeagueId(4664); // The International 6
$matches = $mapper->load();

This parameter works fine and the response contains only 18 matches (not 500). Howerer, total_results value is 12 for some unknown reasons. There is also another bug with using leagueid. There is a known fact that API may return not all matches that satisfy the criterion. At the moment, API returns only 190 matches for TI6, but there are almost 230 of them (using only leagueid filter and not accound_id or something else). The reason is unclear. And nobody knows if it is going to be fixed.

There are also few parameters on the page wiki-GetMatchHistory that may be used as filters. They work with varying degrees of success, or don’t work at all. To bad.

Let’s speak about saving matches to the local DB and getting them out from it.

Matches are saved to the DB one by one:

$mapperDb = new Dota2Api\Mappers\MatchMapperDb();
foreach($matches as $match) {
    $mappedDb->save($match);
}

There is nothing more to tell about. Moving to reading matches from the DB. dota2-api has class Dota2Api\Mappers\MatchesMapperDB for this. There are a lot of filters that really work and are not fiction.

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$matches = $mapper->load();

The code shown above just returns all matches in the DB. Simple and cheerful. What should we do to get only matches for some player (we tried to do this with API from the very begining)?

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$matches = $mapper->load();

There is a known fact that AB plays a lot using Lone Druid. Filter for hero_id may be used to get this matches:

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setHeroId(80); // Lone Druid
$matches = $mapper->load();

Both filters are used with «AND», so the result contains only AB matches where he have played with Lone Druid.

leaguid parameter is also available as a filter. Its usage is the same as for MatchesMapperWeb:

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->setLeagueId(4664); // The International 6
$matches = $mapper->load();

dota2-api also gives you a chance to filter matches with team_id. The Alliance has id equal to 111474 (we will discuss how to get this value in the next posts).

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->setLeagueId(111474); // The Alliance
$matches = $mapper->load();

This filter checks both radiant and dire teams.

As you may see, MatchesMapperDb allows to filter combinations. I.e. filter «all matches for AB on the TI6 where he have played with Lone Druid» will look like:

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->setLeagueId(4664);      // The International 6
$mapper->setAccountId(76482434); // Admiral Bulldog
$mapper->setHeroId(80);          // Lone Druid
$matches = $mapper->load();

2 matches will be returned if your DB contains all TI6 matches (currently only 227 qualifiers matches)s — first one against PR (2463703523) and another against Ad Finem (2467484798).

We’ve already discussed the process of reading and storing matches from/to the DB. Updating matches in the DB doesn’t make any sense, because their data doesn’t change after they are finished. So, only letter D (delete) is left from the classic CRUD. Matches deleting operation is very simple. MatchesMapperDB has method delete that gets list of the match identifiers and deletes all appropriate matches (general data, players, pick and bans etc).

$mapper = new Dota2Api\Mappers\MatchesMapperDb();
$mapper->delete([2463703523, 2467484798]); // two matches from previous example

That’s all concerning to the simple CRUD for matches. I may give one more piece of advice. You should not expect to load all needed matches for the one time. I.e. API doesn’t currently return all TI6 matches. It would be nice to load all available matches for TI6 and save new one to the DB every two hours (while qualifiers were running) . In dota2statistic.com we did the next script every 10 minutes using Cron:

$mapperWeb = new Dota2Api\Mappers\MatchesMapperWeb();
$mapperDb = new Dota2Api\Mappers\MatchMapperDb();
$ti6 = 4664;
$mapperWeb->setLeagueId($ti6);
$mapperDb->setLeagueId($ti6);
$matchesFromApi = $mapperWeb->load();
while ($mapperWeb->getResultsRemaining() != 0 && count($matchesFromApi) > 0) {
    $lastMatchId = -1;
    foreach($matchesFromApi as $match) {
        $mapperDb->save($match);
        $lastMatchId = $match->get('match_id');
    }
    $mapperWeb->setStartAtMatchId($lastMatchId - 1);
    $matchesFromApi = $mapperWeb->load();
}

, ,

Оставить комментарий

Top ↑ | Main page | Back