我正在使用Laravel php和sql创建一个推荐系统。用户在注册过程中输入值,并将它们存储在用户表中。
这是我的用户表架构,任何具有建议名称格式的字段,例如RecommendationLocation是系统应搜索的用户的位置。
TABLE `users` (
`id` (int),
`username` (varchar),
`email` (varchar),
`password` (varchar),
`age` (varchar),
`location` (varchar),
`country` (varchar),
`userType` (varchar),
`religion` (varchar),
`variable1` (varchar),
`variable2` (varchar),
`recommendationAge` (varchar),
`recommendationLocation` (varchar),
`recommendationReligion` (varchar),
`recommendationVariable1` (varchar),
`recommendationVariable2` (varchar),
`recommendationUserType` (varchar),
`recommendationHairColor` (varchar),
`recommendationCountry` (varchar),
)
以下陈述将是一次完美的直接用户匹配,但并非所有用户都将输入相同的信息。我的问题是,由于存在大量的组合,因此必须考虑许多不同的变量。因为我希望即使用户没有某些匹配信息也仍然可以找到用户。例如,该语句只能有一个匹配字段,但查询仍返回带有该匹配字段的用户名。
$recommendationQuery = DB::table('users')
->select('username')
->where('id', '!=', Auth::id()) // Can't be the current Auth User Details
->where('age', '=' , Auth::user()->recommendationAge) // This is a required where clause for all statements
->where('location', '=', Auth::user()->recommendationLocation) // This is a required where clause for all statements
->where('religion', '=', Auth::user()->recommendationReligion)
->where('variable1', '=', Auth::user()->recommendationVariable1)
->where('variable2', '=', Auth::user()->recommendationVariable2)
->where('age', '=', Auth::user()->recommendationAge)
->where('location', '=', Auth::user()->recommendationLocation)
->where('country', '=', Auth::user()->recommendationCountry)
->where('hairColor', '=', Auth::user()->recommendationHairColor)
->get();
有没有其他更有效的方法? 谢谢
答案 0 :(得分:1)
如上所述,允许对单个属性进行匹配的方法是使用逻辑析取(OR
):
DB::table('users')
->select('username')
->where('id', '!=', Auth::id())// Can't be the current Auth User Details
->where('age', '=', Auth::user()->recommendationAge)// This is a required where clause for all statements
->where('location', '=', Auth::user()->recommendationLocation)// This is a required where clause for all statements
->where(function ($query) {
$query->where('religion', '=', Auth::user()->recommendationReligion)
->orWhere('variable1', '=', Auth::user()->recommendationVariable1)
->orWhere('variable2', '=', Auth::user()->recommendationVariable2)
->orWhere('age', '=', Auth::user()->recommendationAge)
->orWhere('location', '=', Auth::user()->recommendationLocation)
->orWhere('country', '=', Auth::user()->recommendationCountry)
->orWhere('hairColor', '=', Auth::user()->recommendationHairColor)
})
->get();
->where(function ($query) { ... })
表示法是Eloquent在结果SQL查询中引入括号的方法。自AND
takes precedence over OR
起,必须使用这些括号。
作为一种更优雅的方法,请考虑将用于配对的属性移至辅助表:
TABLE `user_properties` (
`id` (int),
`user_id` (int)
`property` (varchar),
`value` (varchar),
`recommendation` (varchar),
UNIQUE KEY(user_id, property)
)
以面向列的方式存储属性将使您能够优雅地构造查询以查找所有属性recommendation
与另一个用户的值匹配的情况:
SELECT other_user.user_id, user.property, user.recommmendation, other_user.value
FROM user_properties user
JOIN user_properties other_user
ON other_user.property = user.property
AND other_user.value = user.recommendation
AND other_user.user_id != user.other_id
WHERE user.user_id = ?
({?
是当前用户的占位符,您希望为其找到匹配项。)
然后,您可以计算每个其他用户的匹配属性的数量,并将其作为得分,并选择N个最佳匹配项:
SELECT other_user.user_id, COUNT(*) AS score
FROM user_properties user
JOIN user_properties other_user
ON other_user.property = user.property
AND other_user.value = user.recommendation
AND other_user.user_id != user.other_id
WHERE user.user_id = ?
GROUP BY other_user.id
ORDER BY score DESC
LIMIT 10
答案 1 :(得分:1)
当前,您的代码生成类似以下SQL的内容:
SELECT username
FROM users
WHERE
id =! ? AND age = ? AND location = ?
AND religion = ? AND variable1 = ? AND ...
要匹配用户,需要在WHERE
子句中满足所有条件。
据我了解,您正在尝试将强制性条件与可选性条件分开,例如:
SELECT username
FROM users
WHERE
id =! ? AND age = ? AND location = ?
AND (
religion = ? OR variable1 = ? OR ...
)
使用此查询,用户需要匹配id
,age
和location
上的3个强制条件,以及 any 可选条件({{ 1}},religion
,...)。
要实现此目的,您可以像这样使用Lavarel parameter grouping >
variablbe1