2010-06-13 7 views
1

Supposons que chaque personne possède une collection de livres préférés.Quelle est la meilleure façon de calculer la similarité entre les lignes d'une table en fonction de l'association?

J'ai une table pour:

  • Personne
  • Livre
  • L'association entre la personne et du livre (table commune pour MxN)

Je veux aller chercher les personnes qui sont similaires à une Person1 basée sur les Livres préférés qui se chevauchent. Autrement dit: plus ils ont de livres en commun, plus ils sont similaires.

Je n'ai pas besoin d'utiliser SQL uniquement pour résoudre ce problème. Je pourrais utiliser la programmation aussi. J'utilise SQL Server 2008 et C#.

Quelle solution utiliseriez-vous?

Répondre

2

Cela peut ne pas être le plus efficace, mais il est relativement simple:

WITH SimlarBookPrefs(person_id, similar_person_id, booksInCommon) AS 
(
Select p1.person_id, p2.person_id AS simlar_person_id, 
/* Find the number of books p1 and p2 have in common */ 
    (SELECT COUNT(*) FROM PersonBook pb1, PersonBook pb2 
    JOIN pb1=book_id=pb2.book_id 
    WHERE pb1.person_id=p1.person_id AND pb2.person_id=p2.person_id) As BooksInCommon 
    FROM Person p1 CROSS JOIN Person p2 
) 

Cela vous donnera pour chaque personne, une liste d'autres personnes et les livres numériques en commun.

Pour obtenir la personne la plus proche, ajouter (dans la même requête)

SELECT TOP 1 similar_person_id FROM SimilarBookPrefs 
    WHERE person_id = <person_to_match> 
    ORDER By booksInCommon DESC; 

La première partie ne doit pas être un CTE (c.-à-AVEC ...) il peut être vue ou même un table dérivée. C'est un CTE ici pour la brièveté.

0

Le problème que vous décrivez est généralement appelé «filtrage collaboratif» et abordé à l'aide de «systèmes de recommandation». Googling pour l'un de ces termes devrait vous conduire à beaucoup d'informations utiles.

1

Si je fais cela en C#, je pourrais aborder comme ça

var query = from personBook in personBooks 
      where personBook.PersonId != basePersonId // ID of person to match 
      join bookbase in personBooks 
      on personBook.BookId equals bookbase.BookId 
      where bookbase.PersonId == basePersonId // ID of person to match 
      join person in persons 
      on personBook.PersonId equals person.Id 
      group person by person into bookgroup 
      select new 
      { 
       Person = bookgroup.Key, 
       BooksInCommon = bookgroup.Count() 
      }; 

Cela pourrait probablement être fait avec le cadre de l'entité ou LINQ to SQL, ou simplement dans SQL directement traduit.

exemple de code complet

class CommonBooks 
{ 
    static void Main() 
    { 
     List<Person> persons = new List<Person>() 
     { 
      new Person(1, "Jane"), new Person(2, "Joan"), new Person(3, "Jim"), new Person(4, "John"), new Person(5, "Jill") 
     }; 

     List<Book> books = new List<Book>() 
     { 
      new Book(1), new Book(2), new Book(3), new Book(4), new Book(5) 
     }; 

     List<PersonBook> personBooks = new List<PersonBook>() 
     { 
      new PersonBook(1,1), new PersonBook(1,2), new PersonBook(1,3), new PersonBook(1,4), new PersonBook(1,5), 
      new PersonBook(2,2), new PersonBook(2,3), new PersonBook(2,5), 
      new PersonBook(3,2), new PersonBook(3,4), new PersonBook(3,5), 
      new PersonBook(4,1), new PersonBook(4,4), 
      new PersonBook(5,1), new PersonBook(5,3), new PersonBook(5,5) 
     }; 

     int basePersonId = 4; // person to match likeness 

     var query = from personBook in personBooks 
        where personBook.PersonId != basePersonId 
        join bookbase in personBooks 
        on personBook.BookId equals bookbase.BookId 
        where bookbase.PersonId == basePersonId 
        join person in persons 
        on personBook.PersonId equals person.Id 
        group person by person into bookgroup 
        select new 
        { 
         Person = bookgroup.Key, 
         BooksInCommon = bookgroup.Count() 
        }; 

     foreach (var item in query) 
     { 
      Console.WriteLine("{0}\t{1}", item.Person.Name, item.BooksInCommon); 
     } 

     Console.Read(); 
    } 
} 

class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Person(int id, string name) { Id = id; Name = name; } 
} 

class Book 
{ 
    public int Id { get; set; } 
    public Book(int id) { Id = id; } 
} 

class PersonBook 
{ 
    public int PersonId { get; set; } 
    public int BookId { get; set; } 
    public PersonBook(int personId, int bookId) { PersonId = personId; BookId = bookId; } 
} 
Questions connexes