将单个记录的最佳匹配集放入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;
   }
}

这对于将FamilyCodeCommonCode以及一些逻辑扩展到单独的ModelOptionVersion记录(foreach Model in Family...(来说都是很好的。然而,困扰我的是如何将一组ModelOptionVersion记录最匹配回FamilyCodeCommonCode代表。

如果这是福特(不是(,数据可能看起来是这样的:

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燃气发动机卡车"来定价。他们不仅想在创造价格记录时看到这种情况,而且想在以后回头看的时候看到这种情况。因此,我需要一种方法,不仅扩展FamilyCodeDataCode成员,而且将它们汇总起来。但从数据来看,数据的来源并不一定显而易见。此外,该系统应该足够智能,当有人说"这只适用于F-250和F-350"时,系统会说"使用SuperDuty"。

在我看来,我需要某种最佳匹配的解决方案,也许是一些轻量级的模糊逻辑。是否存在用于此的.NET库?我必须从头开始制作吗?我怎样才能做到这一点?

将单个记录的最佳匹配集放入c#中的组代表中

然而,困扰我的是如何最好地匹配一组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();