anchor.diff:         float descMatches.Length
          float descMatches.Length / float uniqueWords.Length
          float attrMatches.Length
  +       (if attributes.Length > 0 then 1. else 0.)
  +       float (attrNameMatches |> Seq.length)
          queryTitlePosScore
   //       float attrMatches.Length / float uniqueWords.Length
          float brandNameMatch |]
   
  -let getAttr attribMap productId =
  +let attributes attribMap productId =
       match attribMap |> Map.tryFind productId with
  -    | Some a ->
  -      let getAttrStr name (value:string) =
  -          match value.ToLowerInvariant() with
  -          | "yes" -> name // if true attrib, include attrib name
  -          | "no"  -> String.Empty
  -          | _     -> name + " " + value
  -      a |> Seq.map (fun (_, name, value) -> getAttrStr name value) |> Array.ofSeq
  -    | None -> [||]
  +    | Some a -> a |> Seq.map (fun (_,k,v) -> k, v)
  +    | None -> Seq.empty
   
   let getFeatures attribs attribMap sample =
       sample |> features attribs (brandName attribMap sample.ProductId)
  
positive.code: //0.48737 = kaggle rsme; oobrmserror = 0.4776784128; rmserror = 0.4303968628
  //? = kaggle rsme; oobrmserror = 0.4147019175; rmserror = 0.3529753185
  //0.48371 = kaggle rsme; RDF RMS Error: 0.451875; Out-of-bag RMS Error: 0.475592
  
negative.code:   let samples, trainOutput = Array.unzip examples
  
    printfn "Extracting training features..."
    let attribs = attributes attribMap
    let getFeatures' = getFeatures attribs attribMap
    let trainInput = samples |> extractFeatures getFeatures'
    // NOTE: ALGLIB wants prediction variable at end of input array
  