Talk:Darkcanuck/RRServer/Query

From Robowiki
Jump to navigation Jump to search

Desired queries

I'm currently interested in queries to enable tweets about RoboRumble entrants once they've achieved a stable rating. For that, I think I'd need the following:

  • PARAMS: Bot/Version, Rumble; RETURN: Battle count
  • PARAMS: Bot/Version, Rumble; RETURN: APS
  • PARAMS: Bot/Version, Rumble; RETURN: Ranking (eg, 9th)

These might be nice, so I'll post them for sake of brainstorming, but they're not needed by me:

  • PARAMS: Bot/Version, Rumble; RETURN: Glicko-2
  • PARAMS: Bot/Version, 1v1 or Melee; RETURN: Lowest weight class
    • Can be deduced from querying with each of the 4 rumbles, anyway.
  • PARAMS: Bot/Version, Rumble; RETURN: Pairings complete? (boolean)
    • Can be assumed complete for battle count > 2000.

--Voidious 14:37, 6 August 2009 (UTC)

Any reason you list the first three ones separate? Wouldn't it make sense to have one query get all three of those things about a bot, since a number is so much smaller than a http header, wouldn't it be easier to just get all of those at once? --Rednaxela 21:14, 6 August 2009 (UTC)
No particular reason, it could certainly get them all at once. One potential benefit to separating out battle count is that I wouldn't need APS / ranking until battle count reached a certain threshold, and I think ranking is a lot more overhead than the other two (requires sorting all the bots by APS). --Voidious 21:32, 6 August 2009 (UTC)
One basic query could get you the entire row (minus rank #) from the any rankings table based on bot name and game type. Or you could get the whole table, sort it yourself by whatever column you wish. I'd rather keep the # of query types small and their functions general and then users consuming that data can do sorting, comparing, etc. --Darkcanuck 05:45, 7 August 2009 (UTC)
Yep, makes sense. Those two queries (get row, get all rows for a given bot/rumble) would do everything I need. --Voidious 12:48, 7 August 2009 (UTC)

The one I'd mostly be interested in would be the following:

  • PARAMS: Rumble, Timestamp(optional); RETURN: All paring details (bot names, score, survival, maybe battle count) in Rumble (that had a battle since Timestamp).

It would make it easy to get/update test data for doing analysis of how bots do against other bots.

--Rednaxela 15:43, 6 August 2009 (UTC)

Pairing data (ie summarized battles for each pair) or raw battle data? It sounds very expensive... How would you use this? --Darkcanuck 05:45, 7 August 2009 (UTC)
Pairing data, not raw battle data I mean. I was thinking of doing a huge clustering of all 269011 pairings, across 734 dimensions (one for each bot). Essentially, the same data as RatingDetailsJson, except 1) the pairings about all bots not just one, 2) being able to filter out data that's not new, and 3) Don't care about Ranking/ExpectedScore/PBI. Once this huge clustering is computed, the cluster centers could be used to categorize bots, and potentially reveal hidden categories of bots that aren't well known on the wiki. I really think the result of such a clustering would be immensely interesting :) --Rednaxela 06:28, 7 August 2009 (UTC)

I was also interested in pairing data for all bots. It could be used to prioritize battles in a more efficient manner than simply aiming for 2000 battles. For example, pairings that never occurred having priority over other battles, pairings with fewer battles having more priority and/or bots pairing with retired bots having priority. The rankings would stabilize A LOT faster (hours instead of days) and the BATTLESPERBOT parameter will no longer be needed. But the only ways to retrieve this pairing data right now are hammering on the "query=pairing" once for each bot, or parsing the ranking pages. --MN 20:10, 3 July 2011 (UTC)

Actually that's the best way to get the pairings -- returning them all in one glob would be way too much data... I never did implement Rednaxela's query because filtering out old results would likely be too much for the server. I'm working on another web project right now and may have some ideas to improve the rumble database, but it's been awhile. --Darkcanuck 21:17, 3 July 2011 (UTC)

Actually, the BATTLESPERBOT method has an annoying flaw when mini/micro/nanobots are added to the rumble. Since there are less bots there, the client keeps generating mini/micro/nano battles long after those rankings have stabilized. --MN 20:10, 3 July 2011 (UTC)

I agree with you -- I posted a complaint about the "unfairness" of the smaller leagues (taking cpu time away from the main rankings) but there wasn't enough support to change it. It was a long time ago (haven't posted much in past year or so) so not sure where to link to... Darkcanuck 21:12, 3 July 2011 (UTC)

Compressing the data

I'm thinking, some of this stuff could be quite a bit of data. Perhaps it would be better to put it all into a zip file before returning it? --Skilgannon 19:48, 6 August 2009 (UTC)

Err... zip file? A raw deflate or gzip stream would be less overhead and much saner. Zip files are for archiving groups of files, not compress raw data. Actually, if the web server is set up correctly, it can transparently compress anything coming out of it as it sends to the client, so long as the client said in the http header that it accepts compressed responses (which as a note, firefox for one does on any web page). Anyway, might I suggest that maybe the query results should be encoded in JSON, since this is a very simple low-overhead format, which php has a builtin function to serialize to? --Rednaxela 20:57, 6 August 2009 (UTC)

I'm pretty sure my server is setup to send a gzip stream if the client can handle it. No zip files though, just a plain text stream that other apps can consume easily. JSON was exactly what I was thinking, it's a simple structure and already used by ABC's very cool LRP graphs. (try using RatingDetailsJson instead of RatingsDetails to see an example). --Darkcanuck 05:45, 7 August 2009 (UTC)
Just tested here, and yes, it does gzip it if the client asks nicely :) --Rednaxela 06:22, 7 August 2009 (UTC)

Applications

Well, I was eager to flesh out the rest of the logic in the Rumble tweeting script, so I got it working with parsing the RR server pages. (Developed with local copies, then final tests on the actual URLs.) I figured that if I wrote it right, it would be very simple to switch over to the query API later. I've only run it at long intervals as of last night (and killed it for now), but I think the result is pretty cool: twitter/roborumble. It watches the 1v1 and Melee participants lists; when a new version's added, it fetches / caches the rating info for the old version; when the new version hits 2000 battles in General, it tweets. It will also print the same style of results for the bot's lowest weight class if it's a MiniBot or lower, and slightly different text for a new bot (not new version). --Voidious 17:44, 9 August 2009 (UTC)

You can re-enable it, nothing to do with Diamond's troubles. --Darkcanuck 19:50, 9 August 2009 (UTC)

I also wanted to mention another idea I had that could make use of the query interface. I know that I have become super lazy in updating Diamond/Version History, perhaps in part because pasting the URLs and transcribing all the APS/ranking info feels tedious. Well, maybe I could write a MediaWiki extension that would let you write something like [[RumbleLink|minimelee|voidious.mini.BrokenSword 1.04]], and it would formulate the link, fetch the rating/ranking info, and insert a line like I have on Diamond's version history. (I'm thinking it would run once when you make the edit, not every time the page is viewed.) Or I could do it via a form like the UseMod table converter, if the MediaWiki extension doesn't work out. --Voidious 17:44, 9 August 2009 (UTC)

That would be pretty neat. Will be working on the server today, might take a stab at the interface... --Darkcanuck 19:50, 9 August 2009 (UTC)

Feedback

Ok, the first two query types are live. Future ones to come are for pairings (full set for one bot, plus single pairing result) and battles (full set for one pairing). Rednaxela's request for recently updated pairs will be evaluated after that. Request your keys, play with the interface (gently) and post your feedback here. The API is not yet set in stone, I'm willing to make changes to make it useable. --Darkcanuck 05:34, 16 August 2009 (UTC)

Note that the MINE type of JSON is application/json. It may produce 406 Not Acceptable with JSON client request with "Accept: application/json". I did get that sometimes when I try it (via Telnet/NetCat) » Nat | Talk » 10:06, 16 August 2009 (UTC)

Interesting, I'll look into it. The API right now sends nothing special as headers, just the data. --Darkcanuck 17:44, 16 August 2009 (UTC)

This is great, Darkcanuck, thanks. I'm just tinkering with it now. I have a question about Glicko-2. Right now, DrussGT in the rumble shows a Glicko-2 rating of 2187.7 (3, 0.003). This is the info I get for DrussGT when I query the "roborumble" rankings:

  battles: 2147
  bot_id: 1222
  count_wins: 736
  created: 2009-08-10 13:45:44
  name: jk.mega.DrussGT 1.3.10
  pairings: 738
  rating_classic: 1854.737
  rating_glicko: 1879.878
  rating_glicko2: 1878.26
  rd_glicko: 0.895
  rd_glicko2: 3.372
  score_dmg: 79.848
  score_pct: 86.827
  score_survival: 93.978
  state: 1
  timestamp: 2009-08-16 15:51:12
  vol_glicko2: 3.371

How is the Glicko-2 displayed via the web related to the data shown above? (1878.26 is very close to 300 below what the web server gives, but not exactly.) I actually don't need Glicko-2, anyway, but the discrepancy caught my eye when testing this stuff. --Voidious 17:10, 16 August 2009 (UTC)

Good catch! A long time ago Skilgannon suggested scaling Glicko2 to match the ELO scale (of the day). I calculated a scaling factor using the numbers from that time period but didn't want to mess around in the database, so the scaling is applied when the table is displayed. Looks like the query interface is missing that -- easy to fix. I also have a few new queries ready to go on my test server, plus some formatting changes -- will upload in the next hour or so. --Darkcanuck 17:42, 16 August 2009 (UTC)

I've got my rumble Twitter script updated to use the query API. One comment and one question about error messages:

  • I almost feel silly even mentioning this one, but: message: ERROR: Could not find bot "voidious.Dookious 3.0 in database! Just missing a closing quote.
  • What does the error message look like for rate limit exceeded?

As of now, if it encounters any error besides "Invalid robot name" or "Could not find bot", it immediately exits (and, after a few changes, won't get confused next iteration... I think). I doubt it would hit the rate limits very often, but if enough bots were entered/updated at once, it would. Once I learned how to work with JSON, it was all very easy to work with. Very cool. --Voidious 20:02, 16 August 2009 (UTC)

I may have broken your script with the latest update -- after adding the new queries I went back and re-arranged the JSON data for all so that they're consistent. Basically the data field will always contain an array of recordsets, regardless whether the query returns multiple (eg. rankings, details) or a single (eg. participant, pairing) record. And the ranking field has been moved to become part of each record. Fixed the missing quote - thanks! The rate error will set "error=1" and the message will be "Too many requests per hour/minute (<number>) - try again later." Try hitting it 10 times in a browser to see it in action. Nat, I've added the content type which means that I had to switch to using the JSONView FF extension to test the results. =) --Darkcanuck 20:25, 16 August 2009 (UTC)

Yes, that was some funny timing. =) Anyway, updated and working again. --Voidious 20:39, 16 August 2009 (UTC)

Which queries are you using and how often? Some of them are less than optimal, so I want to know if they're worth improving (it doesn't matter so much for the page views). And if there's a better way to present some of the data, let me know. --Darkcanuck 21:12, 16 August 2009 (UTC)

I'm using both of the first two queries, "rankings" and "participant". The script is currently running at 15 minute intervals. I can't imagine it ever going over the 60 per hour limit, and I just updated it to sleep for a minute if it exceeds the per minute interval. There's basically 3 different things it does:

  • If a new version of a bot is added to the participants list, it tries to fetch the rating / ranking of the old version, both in General and in its smallest weight class. This is the part that can generate a lot of queries. It first checks the full rankings, and if the bot's already retired, it queries the bot specifically and deduces its ranking based on APS. It goes down each weight class until it's not present to deduce the smallest weight class. So for MicroBots and NanoBots, when the old version's already retired, it's going to do 8 queries. This could be optimized down to a max of 6, since I don't need the ranking for the weight classes in between, but it would require a little refactoring.
  • For new bots/versions that it's watching until they hit 2,000 battles, it just queries the General rankings to get the battle count. This could query the bot specifically, instead, but that would also create more (albeit cheaper) queries when there are multiple bots on the watchlist. If you think it's preferable, I'll change it to do the participant query instead.
  • Once a bot hits 2,000 battles, it uses the rating/ranking that it just fetched, and also looks for the rating/ranking in its smallest weight class. So up to 3 additional rankings queries when that happens (since there's no way it's retired).

During one iteration of the script, it caches any rankings queries it does. If a few 1v1 NanoBots and a few Melee NanoBots were all added at the same time, it would be a lot of queries, but that seems like a rare occurrence. I can think of a few more ways to optimize it down, too, but right now, it's not ever coming anywhere close to 60 per hour. In the last 72 hours of watching Melee/1v1 rumbles, it's done ~280 queries (URL fetches before, API queries now). --Voidious 22:41, 16 August 2009 (UTC)

Was just curious, your usage seems very moderate to me. =) The 'participant' query is the ugliest one on the server side -- since it's the one you're using the most I'll spend some time tweaking it. --Darkcanuck 22:58, 16 August 2009 (UTC)
Well, I'm glad to hear that. =) It seems moderate to me, too, but I'm not the one spending machine resources running the server. The participant query must still be cheaper than rankings, right? And as of now, most queries of mine are probably rankings, since that's how it's checking battle count. Switching those to participant could be much easier on the server, even if it's more queries, right? --Voidious 01:19, 17 August 2009 (UTC)
Actually, no. The participants query reused a function I already had built (actually all the queries do) but for some convoluted reasons it actually pulls the whole rankings list for that game (which gets cached) then extracts the specific bot. And if the bot was retired, it goes back to the db and gets just that lone record. So the way things stand today, participant queries can actually cost more than rankings. But don't change your setup -- it makes sense and I need to make a better participant query anyway. --Darkcanuck 01:59, 17 August 2009 (UTC)