You could use something like $\text{key}(x,y) = 2^{15}x + y$, where $x$ and $y$ are both restricted to the range $[0, 2^{15}]$. In programming terms, this just means stuffing $x$ into (roughly) half of your 31-bit space and $y$ into the other half.
It sounds like you are using a 32-bit integer variable in some programming language to represent the key. This is the reason for the limit of 2,147,483,647, I suppose. This means you really only have 31 bits available, because one bit is reserved for the sign of the integer. But this is slightly wasteful. If you use an unsigned integer variable (which is available in most programming languages), then you'll have 32 bits available. You can then use 16 bits for $x$, and 16 bits for $y$.
Using this sort of approach, recovering $x$ and $y$ from a given key is easy to code and extremely fast -- you just grab the relevant bits from the key variable. I can write the code, if you don't know how.
If you still want to use an int variable for the key (k), then the code (in C#) is:
int k = 32768*x + y;
With this approach, we require $x \le 65535$ (16 bits) and $y \le 32767$ (15 bits), and k will be at most 2,147,483,647, so it can be held in a 32-bit int variable.
If you are willing to use an unsigned int variable for the key (k), instead, as I suggested, then the code (again in C#) is:
uint k = 65536*x + y;
With this approach, we require $x \le 65535$ (16 bits) and $y \le 65535$ (16 bits), and k will be at most 4,294,967,295, which will fit in a 32-bit unsigned int variable.