2017-04-11 10 views
6

は、私は、PostgreSQLのテーブル含むいくつかの車百万レコードを持っている:postgresqlでマルチカラム推奨エンジンを作成するには?

+----+--------+------+---------+-----------+-------------+------------+------------+ 
| id | price | year | mileage | fuel_type | body_type | brand | model | 
+----+--------+------+---------+-----------+-------------+------------+------------+ 
| 1 | 4894 | 2011 | 121842 | "Benzin" | "Sedan"  | "Toyota" | "Yaris" | 
| 2 | 4989 | 2012 | 33901 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 3 | 4990 | 2013 | 55105 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 3 | 5290 | 2013 | 20967 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 5 | 5594 | 2008 | 121281 | "Benzin" | "Hatchback" | "Mercedes" | "A170"  | 
| 6 | 4690 | 2012 | 71303 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 7 | 5290 | 2013 | 58300 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 8 | 5890 | 2013 | 35732 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 9 | 5990 | 2013 | 38777 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
| 10 | 6180 | 2013 | 69491 | "Benzin" | "Hatchback" | "VW"  | "up!"  | 
| 11 | 6490 | 2012 | 72900 | "Benzin" | "Sedan"  | "Renault" | "Clio III" | 
| 12 | 6790 | 2012 | 49541 | "Benzin" | "Hatchback" | "Renault" | "Clio III" | 
| 13 | 6790 | 2012 | 46377 | "Benzin" | "Hatchback" | "Renault" | "Clio III" | 
| 14 | 6790 | 2012 | 45200 | "Benzin" | "Hatchback" | "Renault" | "Clio III" | 
| 15 | 6894 | 2007 | 108840 | "Benzin" | "Sedan"  | "VW"  | "Golf V" | 
| 16 | 6990 | 2009 | 54200 | "Benzin" | "Sedan"  | "Renault" | "Mégane" | 
| 17 | 6990 | 2012 | 40652 | "Benzin" | "Hatchback" | "Renault" | "Clio III" | 
| 18 | 6990 | 2012 | 38080 | "Benzin" | "Sedan"  | "Renault" | "Clio III" | 
| 19 | 7290 | 2012 | 28600 | "Benzin" | "Hatchback" | "Renault" | "Clio III" | 
| 20 | 7290 | 2013 | 52800 | "Benzin" | "Hatchback" | "Renault" | "Twingo" | 
+----+--------+------+---------+-----------+-------------+------------+------------+ 

私が推奨エンジンを作成したいと思い、それは例えば、いくつかの様々な基準に基づいて、20の最も「類似」の一致を返すことができます。ユーザーがbrand = 'Renault' AND price < 60000 AND year > 2010の検索を実行すると、検索結果の外に、他の車との類似度は低いが、すべての検索条件に一致するとは限りません。あなたは「ルノークリオ」で検索する場合は

  • たちは、その後'Renault Twingo'が近い一致すぎ
  • 場合は次のとおりです。のような何かをする

    私はルビーでは、いくつかのルールベースのコードを作成しようとしています、どこで、順序句によるとあなたは、このコードに基づいて、などなどその

  • に最も近いものを順

を8000の最大価格を持って、私は、SQLクエリを生成します。

しかし問題は、私が20の異なる列を任意に考慮したい、最初の基準に基づいているためです。また、私は単純なフィルタリング(WHERE)クエリを実行したくないという意味で、推奨が下位互換性があることを望んでいます。代わりに、テキスト類似性アルゴリズムを使用するときと似たようなことをしたい。そこでは、あるフレーズをすべてと比較し、それらのすべての比較スコアを取得して並べ替えることができる。

私はこれを実装する方法について非常に困惑しています。これは、1000のルールとif/thenステートメントをSQLクエリを生成するために定義していないアプローチです。私が使うことができる他のテクニック、あるいはpostgresql以外の技術がありますか?

+0

これはStackOverflowの問題を解決するにはあまりにも難しい(と不明)と思います。 SQLは通常、完全一致を行うのが得意ですが、特定の車種のようなものを検索することは、その核となる機能を超えています。私は(比較的)シンプルな "おおよその"名前の一致を実装しなければなりませんでした。*多少予測可能なクエリ結果(および速度)を持つことができるようにするために、特殊目的インデックスを作成しました。私はあなたが小さいから始まり、そこから成長しなければならないのではないかと心配しています。 – Patru

答えて

1

機械学習のテクニックを適用します。

MADlib http://madlib.incubator.apache.org/はPostgresの拡張機能で、データベース内のさまざまな機械学習アルゴリズムを使用することができます。学び、試してみる価値があります。

あなたのベクトルの線形回帰から始まり、次にランダムなフォレストや他のアルゴリズムを試して、あなたのケースでよりうまくいくものを比較してください(アルゴリズムの品質を評価するトリックは簡単です。 -80%の訓練を行い、残りを使用して訓練されたエンジンからの推定値を取得し、偏差エラーを計算するためにいくつかの関数を使用します。

また、スタンフォードのオンラインコースをお勧めします。オンラインブックと講義はYoutube(すべて無料!)で公開されています:http://mmds.org/。推薦エンジンを構築するための様々な現代的なアプローチがその中で非常によく説明されている。

0

tsvectorの列に「テキスト部分」(行に関連するすべてのテキスト)をキャッシュするのが理想的です。フルテキスト検索を実行し、各単語に「重み」を付けることもできますそのため、検索を実行する際により重要になります。

たとえば、ブランド名の重みを増やすことで、同じブランドの商品をすべて表示して結果を並べ替えることができます。 "fulltext"という名前のtsvectorカラムがあるとします:('Renault & Clio'::tsquery;)を検索すると、すべてのルノーとすべてのClioの結果が表示されますが、最初にClioとなり、次にRenaultとなります。万一、Mercedes Clioが存在する場合は、それも表示されることに注意してください。

ドキュメントは非常に明示的であり、いくつかの例をあげておきます。

この場合、データベースはあなたのために仕事をしません。 Clioが同じブランド(ルノー)を持っているだけのため、近いマッチである場合は、はい、そのトリックを行います。しかし、車の大きさのような(精神的に)他の議論を使うならば、それが都市車なのであれば、あなたはそのアルゴリズムを設計できる唯一の人です。たとえば、価格帯の部分は、フルテキスト検索があなたにとって何かをするものではなく、数値が含まれていて最終的にソートされているかどうかを確認する必要があります(数字が完全一致でない限り)。

最後に、あなたの仕事はまさにその通りです。ユーザー入力に基づいて「スマート」な関数を作成し、データベースに対して実行できる複雑なクエリを定義します。それは長いプロセスですが、間違いなく実行可能です。スマートになるようにしてください。あまりにも多くない場合は、tsvectorがすべてのテキスト列をカバーします。

6

各数値プロパティの計算加重偏差:

deviation = abs(actual_value- expected_value)* property_weight 

は、テキストプロパティの簡略化された計算を適用する:

deviation = (actual_value <> expected_value)::int* property_weight 

は、偏差の和の小さい順に位置することをお勧めします。

例。私たちは、走行距離50000と価格6000と2012からルノートゥインゴハッチバックを探しています:

select *, 
    abs(price- 6000)* 100+ 
    abs(year- 2012)* 10000+ 
    abs(mileage- 50000)* 1+ 
    (body_type <> 'Hatchback')::int* 40000+ 
    (brand <> 'Renault')::int* 100000+ 
    (model <> 'Twingo')::int* 50000 
    as recommendation 
from cars 
order by recommendation 
limit 10; 

id | price | year | mileage | fuel_type | body_type | brand | model | recommendation 
----+-------+------+---------+-----------+-----------+---------+----------+---------------- 
    9 | 5990 | 2013 | 38777 | Benzin | Hatchback | Renault | Twingo |   22223 
    8 | 5890 | 2013 | 35732 | Benzin | Hatchback | Renault | Twingo |   35268 
    7 | 5290 | 2013 | 58300 | Benzin | Hatchback | Renault | Twingo |   89300 
    4 | 5290 | 2013 | 20967 | Benzin | Hatchback | Renault | Twingo |   110033 
    3 | 4990 | 2013 | 55105 | Benzin | Hatchback | Renault | Twingo |   116105 
    2 | 4989 | 2012 | 33901 | Benzin | Hatchback | Renault | Twingo |   117199 
12 | 6790 | 2012 | 49541 | Benzin | Hatchback | Renault | Clio III |   129459 
13 | 6790 | 2012 | 46377 | Benzin | Hatchback | Renault | Clio III |   132623 
14 | 6790 | 2012 | 45200 | Benzin | Hatchback | Renault | Clio III |   133800 
20 | 7290 | 2013 | 52800 | Benzin | Hatchback | Renault | Twingo |   141800 
(10 rows) 

あなたが簡単にプロパティの重みを変更することにより、アルゴリズムを校正することができます。

:例えば、

create table models(id serial primary key, model text, value integer); 
insert into models (model, value) values 
('Twingo', 10), 
('Clio III', 11), -- Clio is more similar to Twingo than to Laguna 
('Laguna', 18) 
--- etc 

をメインクエリで数値プロパティなどの値を使用します。

は、テキストプロパティの多くのsophistcated近似は、あなたがこのような補助テーブルのproperitesに数値を割り当てることができます取得するには

select cars.*, 
    abs(price- 6000)* 100+ 
    abs(year- 2012)* 10000+ 
    abs(mileage- 50000)* 1+ 
    (body_type <> 'Hatchback')::int* 40000+ 
    (brand <> 'Renault')::int* 100000+ 
    abs(models.value- 10)* 50000 -- 10 is a numeric value for Twingo 
    as recommendation 
from cars 
join models using(model) 
order by recommendation 
limit 10; 

最適化に関する注記。プロパティのスコープを厳密に定義できる場合は、パフォーマンスを向上させるためにWHERE句に配置してください。たとえば、クエリが目的のブランド以外のブランドを返すことができない場合、このプロパティの偏差を計算するのは意味がありません。

select *, 
    abs(price- 6000)* 100+ 
    abs(year- 2012)* 10000+ 
    abs(mileage- 50000)* 1+ 
    (body_type <> 'Hatchback')::int* 40000+ 
    (model <> 'Twingo')::int* 50000 
    as recommendation 
from cars 
where brand = 'Renault' -- ! 
order by recommendation 
limit 10; 
関連する問題