この質問は広い範囲のものですが、本当に必要なのは、ベストプラクティスのコード構造または適切なチュートリアルへのリンクだけです。
私はphpとmysqlで動作するCRMに取り組んでいます。現在、検索クエリは次のようになっています。
SELECT * FROM連絡先WHERE名前LIKE '%ric flair%'
今、それは本当に馬鹿げていますが、それはそれが意味することです。実際、準備済みステートメントを使用し、30行以上のクエリをいくつか起動し、多数のテーブルを結合して所有権と残りのすべてを確認しています。
ただし、ユーザーがrick flair
またはric m flair
と入力した場合、検索クエリはユーザーを見つけられません。これで、文字列を%ric%
、%m%
、%flair%
の3つの検索語に分割してそこから作業することができましたが、次に、Ric(およびRick)という名前のすべての人を取得します。その場合は)、そしてRic Flairは検索結果のどこにでもある可能性があります。
私はこれをアマチュアのようにやっているような気がします。検索アルゴリズムに関する情報を調べると、Googleになりたいと思っている人しか見つかりません。
これについてのプロのアドバイスはいただければ幸いです。
明確にするため
これは、連絡先、電話、電子メール、タスク、販売機会、会話、メモを検索し、検索文字列(この場合はRic Flair)に接続されている、または接続されているものを検索するグローバル検索機能用です。
ここでの主な目的は、「よりスマートな」検索を行うことです。たとえば、rick flair
またはric m. flair
と入力しても、上部に連絡先ric flair
が返される可能性が高くなります。連絡先リストにリックという名前の人がいるかもしれません。多分それは姓が一致したからで、それはもっと重要なのでしょうか?それとも私はこれを考えすぎていますか?
Lucene を参照してください。 Javaで記述されていますが、PHPから Zendポート または Solr のいずれかを介して使用できます、CMSに何かを埋め込んだほうがいいのでSolrは解決策ではないかもしれませんが。
つまり、検索可能なすべてのデータから index を作成し、そのインデックスを検索できます。データベースクエリよりもはるかに高速であるという利点があります。スコアリングシステムを実装して、一部のレコードがユーザーとの関連性が高い場合に結果リストの上位に表示されるようにすることもできます。考えられる欠点の1つは、データが更新されるたびにインデックスを更新する必要があることです。
Luceneのアプローチがシナリオに適合しない場合は、PHPとデータベースコードを組み合わせて使用できます。ビューまたはストアドプロシージャが代理インデックスとして機能し、検索可能なデータを集約することができます。あなたは空白で文字列を分割する必要があり、これはかなり遅くなる可能性がありますが、そこに到達します。PHPコードはWHERE句の構築を担当します(あなたはSolrがインスピレーションのソースとして提案のクエリ戦略を実装する方法)Id
、Name
およびScore
がインデックスフィールドとしてあり、2つの連絡先レコードがId=1, FirstName="Ric", LastName="Flair"
およびId=2, FirstName="Ric", LastName="Flare"
インデックスレコードは次のようになります。
+--------------+-------+
| Id | Name | Score |
+----+---------+-------+
| 1 | Ric | 1 |
+----+---------+-------+
| 1 | Flair | 1 |
+----+---------+-------+
| 2 | Ric | 1 |
+----+---------+-------+
| 2 | Flare | 1 |
+----+---------+-------+
例は次のようになります(SQL Server)。
DECLARE @index TABLE (
Id INT NOT NULL,
Name NVARCHAR(50) NOT NULL,
Score INT NOT NULL
)
INSERT INTO @index (Id, Name, Score) VALUES (1, 'Ric', 1)
INSERT INTO @index (Id, Name, Score) VALUES (1, 'Flair', 1)
INSERT INTO @index (Id, Name, Score) VALUES (2, 'Ric', 1)
INSERT INTO @index (Id, Name, Score) VALUES (2, 'Flare', 1)
SELECT
Id,
SUM(Score) AS Score
FROM
@index
WHERE
Name = 'Ric'
OR Name = 'Flair'
GROUP BY
Id
ORDER BY
Score DESC
Ric Flair
は両方の値に一致するため、スコアが高くなり、検索結果の最初に表示されます。
インデックスには、検索結果ページに表示される値として使用されるタイトルおよび要約フィールドを含めることもできます。または、これらの値を事前に選択するビューで結果を結合することもできます。
WHERE
句の条件またはScore
フィールド(さまざまなタイプのレコードまたはプロパティにさまざまなスコアを与えることができます)をいじって、より洗練された検索エクスペリエンスを得ることができます。
Elasticsearch を調べます。
Elasticsearchは一種のドキュメントデータベースです。 MongoDBに少し似ていますが、非常に高度なテキスト検索用に設計されています。 Stack Exchange自体は、ページ上部の検索ボックスにElasticsearchを使用していると思います。 ELK(Elasticsearch、Logstash、Kibanaの略)の一部でもあります。 Luceneの上に構築されていますが、自分で構築する必要はない検索のための追加機能がたくさんあります。
LaravelのElasticsearchを使用するための this package が見つかりました。どういうわけかそれをインフラストラクチャに統合する必要がありますが、見返りに、多くの追加作業なしで非常に強力な検索機能を利用できます。
Solrも同様です。また、Luceneに基づいて構築され、強力な検索機能を提供します。これらはどちらもSQL LIKE
よりも強力で、Luceneを直接使用するよりも簡単な優れた選択肢です。
データを正規化して、Ric Flairを人物エンティティとして最初に検索してから、この人物の連絡先を表示できます。これはBig CRMの1つの方法であり、顧客であるRicがあなたにとって重要である場合に適しています。多くのデータ属性を介して、個人エンティティの高度な検索コントロールを期待する必要があります。
たとえば、注文の代替連絡先として、毎回人を作成したくないことがよくあります。この場合、多くのことはできませんが、データのキャプチャ中に名前フィールドを埋める方法について、明確なパターンや指示をオペレーターに提供します。
もちろん、検索パターンを空白で分割すると、より多くの結果が得られますが、これは標準のパターンではないため、ユーザーはそれを好まないでしょう。