2013-11-28 2 views
3

У меня есть списки product и categories и нужно знать, если каждый пользователь просмотрел их, также общее количество products для каждого category, которые были просмотрены каждым пользователем.Как отслеживать элементы, которые каждый пользователь смотрел

Короче говоря, мне нужно держать списки

  • Продукты, которые каждый пользователь просмотрены (После того, как пользователь просматривает продукт Профиль пользователя он будет добавлен в этот список)
  • Разделы, которые просматривали каждый пользователь (Once пользователь просмотрел профиль категории, он будет добавлен в этот список)
  • Количество товаров в каждой категории, которые просматривали каждого пользователя?

Я добавил две переменные-члены в класс Client следующим образом. Я не уверен, что это правильно или нет, во-вторых, я не знаю, как сохранить счетчик для всех просмотренных продуктов каждой категории для каждого пользователя. (Я знаю, что могу получить его с помощью функции (COUNT) базы данных, но мне интересно, есть ли другой эффективный способ, а не отправлять этот запрос в базу данных).

Клиент:

@Entity 
public class Client { 
    @Id 
    @GeneratedValue 
    private long id; 

    @OneToOne 
    private List<Product> viewedProducts = new ArrayList<Product>(); //keep list of viewed products 

    @OneToOne 
    private List<Category> viewedCategories = new ArrayList<Category>(); //keep list of viewed categories 

    .... 
} 

Продукт

@Entity 
public class Product { 

    @Id 
    @GeneratedValue 
    private long id; 

    @ManyToOne(cascade = CascadeType.ALL) 
    private Category category; 

    .... 
} 

Категория

@Entity 
public class Category { 
    @Id 
    @GeneratedValue 
    private long id; 

    .... 
} 
+0

Таким образом, другой способ означает, что вам нужно добавить логику для этого при каждом нажатии категории и продукта. Подобно u, вы можете создать карту, в которой имя категории будет ключом, а в списке продуктов будет значение – Deepak

+0

. не получить вас, как определить члены переменной тогда? – AlexCartio1

+0

В настоящее время я думаю, что u сохраняет значения экземпляров клиента в db для каждого клика, поэтому, если это не требуется для будущего, тогда вы можете сделать временный список и можете использовать – Deepak

ответ

1

Мое предложение, чтобы те м Эмбер переменные, которые у вас есть в данный момент, и добавьте следующие строки в ваш класс

@OneToMany 
    private List<ViewedProductsPerCategory> = 
            new ArrayList<ViewedProductsPerCategory>(); 

в этом классе вы должны иметь

@Entity 
public class ViewedProductsPerCategory { 
    @Id 
    @GeneratedValue 
    long id; 

    @OneToMany 
    Category category; 

    long CatCounter; 

    long ProCounter; 

    getters and setters; 
} 

НО убедитесь, что держать счетчики в печенье, а не вызывать базу данных каждый время, когда пользователь посещает продукт или категорию. После того, как пользователь выйдет из системы, добавьте числа в cookie в соответствующие счетчики в базе данных.

Проблема: Имейте в виду, что пользователь может удалить файл cookie перед выходом из системы, хотя это очень редко, поскольку большинство пользователей не удаляют свои файлы cookie во время входа в систему, чтобы избежать выхода из системы.

1

Во-первых, вы должны использовать аннотацию @ManyToMany для viewedProducts и viewedCategories. Во-вторых, сколько продуктов существует? Если вам сотни или тысячи, вам может потребоваться выполнить подкачку через просмотренные продукты или получить некоторые из них по контексту или что-то еще. Когда у вас есть коллекция viewedProducts, вы имеете дело со всеми просмотренными продуктами, загружаемыми в память из базы данных, что приводит к потере производительности. Так что вам лучше создать такие объекты:

@Entity public ViewedProduct { 
    @Id private Integer id; 
    @ManyToOne 
    private Client customer; 
    @ManyToOne 
    private Product product; 

    ViewedProduct(Client customer, Product product) { 
     this.customer = customer; 
     this.product = product; 
    } 

    public Client getCustomer() { 
     return customer; 
    } 

    public Product getProduct() { 
     return product; 
    } 
} 

@Entity public ViewedCategory { 
    @Id private Integer id; 
    @ManyToOne 
    private Client customer; 
    @ManyToOne 
    private Category category; 
    @Basic 
    private int viewedProductCount; 

    ViewedCategory(Client customer, Category category) { 
     this.customer = customer; 
     this.category = category; 
    } 

    void incrementViewedProducts() { 
     viewedProductCount++; 
    } 

    public Client getCustomer() { 
     return customer; 
    } 

    public Product getProduct() { 
     return product; 
    } 
} 

public class ProductViewService { 
    private ViewedProductRepository viewedProductRepository; 
    private ViewedCategoryRepository viewedCategoryRepository; 

    public ProductViewService(ViewedProductRepository viewedProductRepository, 
      ViewedCategoryRepository viewedCategoryRepository) { 
     this.viewedProductRepository = viewedProductRepository; 
     this.viewedCategoryRepository = viewedCategoryRepository; 
    } 

    public void viewProductByCustomer(Client customer, Product product) { 
     ViewedProduct vp = viewedProductRepository.find(customer, product); 
     if (vp == null) { 
      vp = new ViewedProduct(customer, product); 
      viewedProductRepository.add(vp); 
      ViewedCategory vc = viewedCategoryRepository.find(customer, product.getCategory()); 
      if (vc == null) { 
       vc = new ViewedCategory(customer, product.getCategory()); 
       viewedCategoryRepository.add(vc); 
      } 
      vc.incrementViewedProducts(); 
     } 
    } 
} 

public interface ViewedProductRepository { 
    ViewedProduct find(Client customer, Product product); 
    void add(VIewedProduct product); 
    List<Product> getRecentlyViewedProducts(Client customer, int limit); 
    // etc 
} 

public class PersistentViewedProductRepository implements ViewedProductRepository { 
    private EntityManager em; 

    public List<Product> getRecentlyViewedProducts(Client customer, int limit) { 
     return em.createQuery(
       "select vp.product " + 
       "from ViewedProduct vp " + 
       "where vp.customer = :customer " + 
       "order by vp.id desc", Product.class) 
       .setMaxResults(limit) 
       .getResultList(); 
    } 

    // etc 
} 

Для подсчета товаров вы должны решить, действительно ли необходима денормализация. Если это действительно так, вы можете выбросить viewedProductCount и использовать запросы JPQL, чтобы получить это количество по мере необходимости.

+0

Вы предложили мне использовать @ ManyToMany, но в коде решения я не смог найти такую ​​аннотацию. это опечатка? Что делает @ Basic? Согласны ли вы с J888, что счетчик должен храниться в файле cookie перед добавлением к значению базы данных? – AlexCartio1

+0

Прочтите внимательно. Я сказал, что в вашем случае '@ ManyToMany' будет решением. Но далее я заметил, что ваш подход приводит к потере производительности и предлагает другой подход, без '@ ManyToMany' вообще. ['@ Basic'] (http://docs.oracle.com/javaee/6/api/javax/persistence/Basic.html) можно здесь пропустить. –

+0

Я не согласен с @ J888, что счетчик должен храниться в cookie, так как файлы cookie всегда отправляются на сервер и со многими продуктами, что приводит к растущему сетевому трафику. Лучше использовать [Хранение HTML 5] (http://www.html5rocks.com/en/features/storage). Но имейте в виду, что значительное количество людей используют браузеры без поддержки Storage. –

0

Если количество просмотров товара по вашему заказу фактически не требуется вашим приложением, а вместо этого является метрикой, необходимой бизнесу/маркетингу для оценки интереса клиентов, то я не думаю, что вы должны поместить эту логику в свою заявление. Существует несколько неинтрузивных способов, которыми вы можете предоставить эту информацию без искажения вашего приложения с постоянной записью БД на каждом просмотре страницы.

В зависимости от того, как каротаж сделано, вы могли бы настроить протоколирование доступа следующим образом:

2013-12-03 17:31:44 user:[email protected] INFO com.acme.web.interceptors.AccessLogInterceptor - URL [/product/1234] 

Затем с помощью анализатора лог инструментов (пользователь Я Heroku, который имеет Logentries дополнения) для сбора бизнес-аналитики Информация. Это также позволяет избежать необходимости писать код для отображения/экспорта данных, все это уже встроено в инструмент.

Другой вариант заключается в использовании Google Analytics, это дает гораздо более подробную информацию о шаблонах просмотра пользователя, понижаются цены и т.д.

0

Было бы сделать вещи проще, если мы добавим к модели предметной области за пару сущности, соответствующие некоторым концепциям, которые могут отсутствовать в модели.

Если это домен маркетинга/продаж, было бы лучше добавить некоторые новые entities, такие как ProductViewEvent и CategoryViewEvent, для первых двух точек, которые указывают на категорию и продукт и содержат все свойства события вида.

. Продукт и сама категория не нуждаются в ссылке на объекты событий, это будет однонаправленное отношение от объекта события к категории/продукту.

В зависимости от домена эти объекты событий могут даже стать value objects, являются ли два события представления полностью взаимозаменяемыми с точки зрения домена?

Для третьего пункта добавьте новый статистический сервис service, который дает сгруппированные итоговые значения, необходимые для метода обслуживания.

Для текущих итогов, если это вызывает проблемы с производительностью, выполняющие COUNT в базе данных, всегда можно добавить атрибут с общей суммой просмотров для категории/продукта.

Но обновляйте эти текущие итоги с помощью запросов пакетного обновления на сервисном уровне формы update total = total + difference where ..., чтобы гарантировать, что итоговые значения сохраняются в соответствии с точки зрения транзакции базы данных.

Лучше не использовать эту оптимизацию, если это не необходимо, это зависит от ожидаемого объема просмотров. у вас есть идея, если она находится на тысячах, миллионных диапазонах?

Смежные вопросы