将单个记录的最佳匹配集放入c#中的组代表中
本文关键字:记录 单个 最佳 | 更新日期: 2023-09-27 18:06:44
我们正在使用代码优先实体开发业务应用程序框架,我正在寻找以下问题的解决方案如果可能的话,不在数据库中。
我们有一个持久性模型,看起来类似于以下内容:
public abstract class DataCode
{
public long Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
public class Option : DataCode
{
// a bunch of stuff that describes an Option
}
public class Model : DataCode
{
// a bunch of stuff that describes a product model
}
public class Version
{
public long Id { get; set; }
// a bunch of stuff that describes a version of the product model
}
public class ModelOptionVersion
{
public Model ThisModel { get; set; }
public Option WithThisOption { get; set; }
public Version UsingThisVersion { get; set; }
// a bunch of stuff that is important to track
// at the intersection of these three properties
}
除了用户希望使用"族代码"answers"公用代码"应用特性值之外,其他操作都很好。为了支持这一点,我认为以下类将起作用:
public abstract class CodeGroup
{
public virtual ICollection<DataCode> DataCodes { get; set; }
}
public class Family : CodeGroup, DataCode
{
public Family(ICollection<Model> Models)
{
base:DataCodes = Models;
}
}
public class CommonCode : CodeGroup, DataCode
{
public Family(ICollection<Option> Options)
{
base:DataCodes = Options;
}
}
这对于将FamilyCode
和CommonCode
以及一些逻辑扩展到单独的ModelOptionVersion
记录(foreach Model in Family...
(来说都是很好的。然而,困扰我的是如何将一组ModelOptionVersion
记录最匹配回为FamilyCode
或CommonCode
代表。
如果这是福特(不是(,数据可能看起来是这样的:
Family | Model
Trucks | F-150
Trucks | F-250
Trucks | F-350
SuperDuty | F-250
SuperDuty | F-350
CommonCode | Option
Gas Engines | 4.6l V-8 Gas
Gas Engines | 5.4l V-8 Gas
Diesel Engines | 6.4l V-8 Diesel
Diesel Engines | 7.3l V-8 Diesel
Diesel Engines | 6.0l V-8 Diesel
Model | Option | Version
F-150 | 4.6l V-8 Gas | 2015
F-150 | 4.6l V-8 Gas | 2016
F-150 | 5.4l V-8 Gas | 2015
F-150 | 5.4l V-8 Gas | 2016
F-250 | 5.4l V-8 Gas | 2015
F-250 | 5.4l V-8 Gas | 2016
F-350 | 5.4l V-8 Gas | 2015
F-350 | 5.4l V-8 Gas | 2016
F-250 | 6.4l V-8 Diesel | 2015
F-250 | 6.4l V-8 Diesel | 2016
F-350 | 6.4l V-8 Diesel | 2015
F-350 | 6.4l V-8 Diesel | 2016
用户希望根据"柴油发动机超负荷"或"2016燃气发动机卡车"来定价。他们不仅想在创造价格记录时看到这种情况,而且想在以后回头看的时候看到这种情况。因此,我需要一种方法,不仅扩展FamilyCode
和DataCode
成员,而且将它们汇总起来。但从数据来看,数据的来源并不一定显而易见。此外,该系统应该足够智能,当有人说"这只适用于F-250和F-350"时,系统会说"使用SuperDuty"。
在我看来,我需要某种最佳匹配的解决方案,也许是一些轻量级的模糊逻辑。是否存在用于此的.NET库?我必须从头开始制作吗?我怎样才能做到这一点?
然而,困扰我的是如何最好地匹配一组ModelOptionVersion记录回FamilyCode或CommonCode代表。
您在这里要做的是找到FamilyCode(或CommonCodes(,以便某个集合中的每个ModelOptionVersion都有一个由该FamilyCode指定的Model。
var desiredModels = // some collection of Models
var familyCodesByFamily = (
from familyCode in db.FamilyCodes
group familyCode by familyCode.Family into family
select family);
var applicableFamilies = (
from family in familyCodesByFamily
where desiredModels.All(dm => family.Any(f=> f.Model == dm))
select family.Key).ToList();
我还没有测量过这种查询的执行情况,但它并没有直接映射到SQL的功能。SQL不直接让你做通用量词("给我x,这样就可以对所有x,y"(,但它确实让你做存在量词("让我x,所以存在y"(和否定。如果事实证明上面的表现不好,那么在语义上应该等效的另一个公式是:
var incorrectFamilies =
(from familyCode in db.FamilyCodes
where !desiredModels.Contains(familyCode.Model)
select familyCode.Family).Distinct();
var correctFamilies =
(from familyCode in db.FamilyCodes
where !incorrectFamilies.Contains(familyCode.Model)
select familyCode.Family).Distinct().ToList();
它们生成了不同的SQL,第一种看起来很自然的选择比第二种选择更复杂。无论您选择哪种样式,CommonCode的代码都应该遵循相同的模板。
编辑:对于真正的模糊匹配,让我们制定两个衡量一组模型和族之间匹配程度的指标。我们称之为"覆盖率"的第一个(也是更重要的(指标,它与家族中包含的型号数量有关。第二个我们称之为"拟合",它与模型集中包含的族成员数量有关(如果您有两个族,这两个族都完全包含所需的模型,则我们希望该族在所需的集合之外具有较少的额外模型(。我们将根据比赛的好坏来排序结果,然后计算我们能处理的结果的数量。
var fuzzyFamilies = (
from family in familyCodesByFamily
let coverage = desiredModels.Average(dm => family.Any(f => f.Model == dm) ? 1.0 : 0.0)
let fit = family.Average(f => desiredModels.Contains(f.Model) ? 1.0 : 0.0)
orderby coverage descending, fit descending
select family.Key)
.Take(resultCount)
.ToList();