2

We have been asked to scope a solution for a new site build that we'd like to use Craft for. There is one requirement I'm not sure how we'd approach though.

In Craft terms, we would have an Articles channel that has a number of fields:

  • Employer (relationship to a single Employer channel entry)
  • Sector (relationship to a single category)
  • Stage (select field)
  • Tag (tag field)

Then each logged in User would also have the same fields on their profile. I guess it would be easy enough to query the user attributes and pass those to a craft()->entries() call, but the requirements call for a very specific sorting algorithm.

That would work something like this:

  • Article Employer matches User Employer = score of 10
  • Article Sector matches User Sector = score of 3
  • Article Stage matches User Stage = score of 4
  • Article Tags intersect with User Tags = score of 1 x number of matches

The result of that score would then be added up and used as a sort dimension against a list all the latest Article entries.

Can anybody suggest a practical (processor efficient) way to achieve this?

My current thinking this:

  1. Get all Article entries.
  2. Loop through each Article them and add the calculated score to an array containing the entry ID and the score.
  3. Order the array by score.
  4. Requery all Articles with pagination enabled, passing in a the list of entry IDs in the order defined by the sorted array.

Would that work? In particular the last step - can we define entries be sorted by an array of ID numbers?

Any other suggestions would be gladly received.

1

Looks like a solid plan to do this. And to get the entry models it the same order as you're passing the IDs to your ElementCriteriaModel there's this property: fixedOrder(true).

Other suggestions could only be to do this with plugin code, but I don't think this would speed up thing noticeably.

| improve this answer | |
  • I think the problem will come in the database load. The number of queries pulling back the categories and tags for all the entries is going to pile up, and as it's per user, it's not something caching would be much help with. I wonder if the category fields could be swapped out for multi-select fields instead to help cut down on that. We could be looking at 1000 article entries so I'm concerned it could grind to a halt. – Russ Back Apr 9 '15 at 18:42
  • I wonder if we can cache the query results of the initial ALL entries and associated category/tag data query, then we just need to do the looping and do a single call to get the paginated entries in order. – Russ Back Apr 9 '15 at 18:57
  • Yes that's always the problem with index pages and relational fields. But you could try and cache the entries per user, using the user's ID as the cache key. – carlcs Apr 9 '15 at 19:21
  • Looks like yii can cache data whereas Craft caches template output so I think we may have a better option there for all users – Russ Back Apr 9 '15 at 19:26
  • 1
    You could also try to reduce the amount of queries with such an approach Get related entry data without extra queries. – carlcs Apr 9 '15 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.