viernes, 27 de junio de 2008

Crear la base de datos de una red social

Crear la base de datos de una red social puede parecer en principio muy complicado, nada más lejos de la realidad, lo que seguramente sea más difícil es optimizar los accesos en caso de que obtenga un gran número de usuarios.

Suponiendo que usamos el modelo relacional, deberíamos crear una tabla de usuarios tal como:

id | datos

Dónde id es un identificador único para cada usuario y datos son los datos específicos que queremos guardar, nombre, apellidos, email, etc.

No todos los datos personales como tales pueden/deben ir ahí, si por ejemplo queremos guardar las aficiones y poder estudiarlas más tarde deberíamos tener una tabla aficiones.

id | aficion


Al igual que podemos crear grupos de usuarios de una forma similar.

id | grupo

Y otra tabla propia a la información de cada grupo.

grupo | informacion_relevante

Con unas consultas simples podemos reconstruir toda la información relativa a estos datos.

La mayor utilidad de las redes sociales es el enlace entre usuarios, así que también necesitaremos guardar esta información en una tabla llamada enlaces o amigos.

id1 | id2

Podemos tener otras si tenemos varios tipos de relaciones (por cierto no me ha parecido ver esto implementado en ninguna red social, tan solo amistad).

Una de las utilidades más usadas de las redes sociales es la de etiquetar a gente en las fotos.
Se me ocurren dos formas de implementarlo, teniendo una tabla global de fotografías (grandísima) o creando una tabla por fotografía (muchísimas tablas). Creo que la segunda escalaría peor que la primera, pero es cuestión de probarlo en un DBMS concreto.

Las otras aplicaciones como tablón, envío de mensajes, solicitudes pendientes de amigos...no difieren demasiado de estas.

Como se puede ver conceptualmente la base de datos de una red social no es nada complicada comparada con otras aplicaciones, sin embargo hay que tener en cuenta que optimizarla para soportar 80 millones de usuarios que tiene facebook debe ser algo más complicado.

miércoles, 25 de junio de 2008

Otra visión de top

Hay varias formas de mostrar los procesos que están ejecutándose en linux, ps, top, pstree...pero hay otro comando menos popular y quizá más útil, htop.

Aquí os dejo una captura de pantalla.



Aparte de estar la información mejor organizada en la pantalla se pueden organizar los procesos por CPU gastada, memoria entre otras cosas, además se puede cambiar la prioridad de procesos, organizarlos en árbol e incluso matarlos.
Todo ello con una tecla.

Modificar cookies

La mayoría de webs en las que hay que registrarse nos mandan cookies con información necesaria para comprobar que somos nosotros. Es posible que nosotros también lo necesitemos para crear nuestras propias webs.

Para depurar, se puede ver cual es el valor actual de las cookies mandada por la página actual usando el siguiente script en la barra de navegación.

javascript:void(document.cookie=prompt("Cambiar cookie",document.cookie).split(";"))

Si queremos, podemos mostrar las cookies separadas por campos para que resulte más claro. Simplemente necesitamos iterar sobre el script anterior.

javascript:for(var g in document.cookie.split(";"))void(prompt("Cambiar cookie "+document.cookie.split(";")[g].split("=")[0],document.cookie.split(";")[g].split("=")[1]));alert("Cookies:\n"+document.cookie.replacer(/;/,"\r\n"));

martes, 24 de junio de 2008

Descomprimir ficheros en python

Para descomprimir ficheros en python podemos usar la librería gzip. Puede resultar muy útil para guardar de forma eficiente el estado de nuestros programas y posteriormente recuperarlo.

Aquí un ejemplo.

#!/usr/bin/python

import gzip;

f=open("prueba.txt", "r");
texto=f.read();
print texto;

print "----------------";

comprimido=gzip.open("prueba.gz", "r");
descomprimido=comprimido.read();

print descomprimido;

Como se puede ver tan solo es necesario llamar al método open del módulo gzip y ya podemos tratarlo como un fichero descomprimido.

Expresiones regulares en python

Uno de los módulos mas interesantes en python es el que se encarga de proporcionarnos las funcionalidades de las expresiones regulares. Este módulo se llama re.

Veamos un ejemplo de uso.

#!/usr/bin/python

import re;

cadena_larga="esto es una cadena muy larga";

if(re.search("cadena", cadena_larga)):
print "caso 1: presente";
else:
print "caso 1: ausente";

if(re.search("ca.ena", cadena_larga)):
print "caso 2: presente";
else:
print "caso 2: ausente";

if(re.search("\s.\s|\s..\s", cadena_larga)):
print "caso 3: presente";
else:
print "caso 3: ausente";

if(re.search("[0-9]", cadena_larga)):
print "caso 4: presente";
else:
print "caso 4: ausente";

if(re.search("[^0-9]", cadena_larga)):
print "caso 5: presente";
else:
print "caso 5: ausente";

if(re.search("ga$", cadena_larga)):
print "caso 6: presente";
else:
print "caso 6: ausente";

En estos ejemplos se está usando el método search, search busca coincidencias en toda la cadena. También existe match que tan solo busca coincidencias desde el principio de la cadena.

El primer ejemplo es el más sencillo, se busca la subcadena "cadena" dentro del texto.

En el segundo se introduce el uso del operador ".", que equivale a cualquier carácter.

En el tercer ejemplo se reúne el OR de dos consultas, palabras de un carácter con espacios a los dos lados y palabras con dos caracteres.

En el cuarto se busca cualquier número que haya en la cadena.

En el quinto justo lo contrario que en el cuarto, la ausencia de números.

En el sexto ejemplo se comprueba si la cadena termina con los caracteres "ga", para comprobar el comienzo de la cadena se usa "^".

Las expresiones regulares no son muy útiles si no podemos recuperar subcadenas de los textos que tratamos, se hace de la siguiente forma.

#!/usr/bin/python

import re;

cadena_larga="esto es una cadena muy larga";

parsed=re.search("(\S+)\s",cadena_larga);
print parsed.groups();

print re.findall("(\S+)\s",cadena_larga);

En el caso de usar search buscamos las primera palabra seguida de espacio, en el caso de findall se devuelve una lista con todas las coincidencias.

sábado, 7 de junio de 2008

Leyendo correo POP3 desde python

Acceder a una dirección de correo electrónico desde python es muy sencillo si se tiene habilitado POP3.

Para ello se puede usar la librería poplib. Para los ejemplos usaré gmail, si queréis probarlo acordaros de habilitar POP3 en la web de gmail.

#!/usr/bin/python

import poplib;

p=poplib.POP3_SSL("pop.gmail.com");
p.user("usuario@gmail.com");
p.pass_("pass");

mensajes=p.list()[1];

lastmsg=mensajes[-1].split()[0];

print p.retr(lastmsg);

p.quit();

Primero creamos un objeto POP3_SSL, (gmail funciona con SSL), metemos usuario y contraseña.
A partir de entonces ya podemos administrar el correo con las funciones que nos provee la librería poplib.

En el ejemplo se obtiene la lista de mensajes con list(), se elige de la respuesta el último mensaje y se le pide al servidor mediante retr(msgid). Es necesario parsear la salida puesto que lo que tenemos hasta el momento es la respuesta en bruto del servidor, pero si leéis en pantalla ya podeis distinguir de que mensaje se trata.

Usando esto podemos crear muy fácilmente un programa que revise nuestro buzón de correo y nos avise cuando nos llega un nuevo mensaje.

#!/usr/bin/python

import poplib;
import time;

oldmensajes=0;
nmensajes=0;
first=1;

while(1):
p=poplib.POP3_SSL("pop.gmail.com");
p.user("usuario@gmail.com");
p.pass_("pass");

nmensajes=p.stat()[0];
print nmensajes;

p.quit();

if(first==1):
oldmensajes=nmensajes;
first=0;


if(nmensajes!=oldmensajes):
print "Se ha recibido " + str(nmensajes-oldmensajes) + " mensaje(s) nuevos";
nmensajes=oldmensajes;

time.sleep(300);

El script no está probado, solo es un ejemplo de como se podría crear algo útil con esta librería.

Importación de módulos en python

En python hay varias formas de importar módulos, la primera de ellas es la siguiente.

#!/usr/bin/python

import math

print math.sqrt(80)

Se importa la librería math pero después para hacer uso de la función sqrt es necesario especificar que viene de esta librería en concreto.

Se hace así para diferenciar que funciones vienen de cada librería y que no haya confusión de a que función estamos llamando.
Si por ejemplo disponemos de una librería matemática más rapida pero menos completa, para sustituir esta llamada se podría hacer math2.sqrt(80) sin ningún problema.

La segunda manera de importar módulos es como sigue.

#!/usr/bin/python

from math import sqrt

print sqrt(80)

En esta ocasión nos ahorramos especificar en la llamada de donde viene la función sqrt pero debe especificarse en la importación.
Esta forma de importar funciones de los módulos hace que quede muy claro que funciones se usan y de donde provienen, además simplifica la sintaxis en la llamada pero tiene un problema; si tenemos en cuenta el ejemplo de antes, debemos saber de antemano que llamadas vamos a usar de math y de math2 y no podríamos usar sqrt de las dos en el mismo programa.

La tercera forma es la siguiente.

#!/usr/bin/python

from math import *

print sqrt(80)

Es igual a la primera pero sin necesidad de indicar el espacio de nombres en cada llamada, tiene el mismo problema de la segunda y en general es considerado un mal hábito de programación. Se están importando multitud de nombres que pueden colisionar con los del programa y no provee ninguna utilidad especial.

En conclusión, para scripts pequeños de unas cuantas líneas me quedaría con la segunda o la tercera por sencillez, pero si se pretende hacer algo más grande y serio la primera opción es la adecuada.