ES实际需求设计展示

作者: 分类: php 时间: 2026-05-08 评论: 暂无评论

APP搜索设计案例demo

use Elasticsearch\ClientBuilder;

public static function singleton()
{
    if (empty(self::$client)) {
        $hosts        = self::getHost();
        $client       = ClientBuilder::create()->setHosts($hosts)->build();
        self::$client = $client;
    }
    return self::$client;
}

[数据同步核心代码]

public static function addAppV2($appInfo)
    {
        $isIos   = intval(stripos($appInfo['platform'], 'IOS') !== false);
        $isAz    = intval(stripos($appInfo['platform'], '安卓') !== false);
        $isH5    = intval(stripos($appInfo['platform'], 'H5') !== false);
        $isYgj   = intval(stripos($appInfo['platform'], 'YGJ') !== false);
        $isYyx   = intval(stripos($appInfo['platform'], 'PCYYX') !== false);
        $isAzH5  = intval($isAz || $isH5);
        $isIosH5 = intval($isIos || $isH5);

        $param = [
            'index' => self::APP_INDEX_V2,
            'id'    => $appInfo['id'],
            'body'  => [
                'id'              => $appInfo['id'],
                'state'           => $appInfo['state'],
                'is_ios'          => $isIos,
                'is_az'           => $isAz,
                'is_ios_h5'       => $isIosH5,
                'is_az_h5'        => $isAzH5,
                'is_ygj'          => $isYgj,
                'is_h5'           => $isH5,
                'is_pc_yyx'       => $isYyx,
                'classid'         => $appInfo['classid'],
                'app_id'          => $appInfo['app_id'],
                'is_az_h5_pc_yyx' => intval($isYyx || $isAzH5),
                'game_name'       => $appInfo['main_title'],
                'subtitle'        => $appInfo['subtitle'] ?? '',
                'title'           => $appInfo['new_title'],
                'mix_type'        => $appInfo['mix_type'] ?? 100,
            ]
        ];

        $addIndex = self::singleton()->index($param);
        return $addIndex;
    }

[搜索核心代码]
同步游戏数据到es数据库,通过function_score 设置权重

游戏名中含有 关键字 完全匹配权重设置10000
搜索词包含在标题中,且比例 ≥ 60% → 高权重
标题包含在搜索词中,且比例 ≤ 200% → 高权重

下载加权 5
日活加权 15
支付加权80

private function searchGameIdsV21()
    {
        $keyword = $this->keyword;

        $must = $mustNot = $scoreFun = [];

        $should[] = [
            'match' => [
                'game_name.keyword' => [
                    'query'     => $keyword,
                    'fuzziness' => floor(mb_strlen($keyword) / 4), // 表示容错字符
                    'boost'     => 1
                ]
            ]
        ];
        $should[] = [
            'match' => [
                'title.keyword' => [
                    'query'     => $keyword,
                    'fuzziness' => floor(mb_strlen($keyword) / 3),
                    'boost'     => 1
                ]
            ]
        ];
        $should[] = [
            'match' => [
                'cates.keyword' => [
                    'query'     => $keyword,
                    'fuzziness' => 1,
                    'boost'     => 1
                ]
            ]
        ];
        $should[] = [
            'multi_match' => [
                'query'  => $keyword,
                'fields' => [
                    'game_name', 'subtitle'
                ],
                'boost'  => 1,
            ]
        ];

        // 增加包含全量游戏名的权重
        $scoreFun[] = [
            'filter' => [
                'term' => [
                    'game_name.keyword' => $keyword,
                ]
            ],
            'weight' => 10000
        ];
        $scoreFun[] = [
            'filter' => [
                'term' => [
                    'title.keyword' => $keyword,
                ]
            ],
            'weight' => 10000
        ];
        $scoreFun[] = [
            'filter' => [
                'script' => [
                    'script' => [
                        'source' => "String title = doc['title.keyword'].value;title.contains(params.query) && (params.query.length() / (double) Math.round(doc['title_length'].value)) >= 0.6 || params.query.contains(title) && (params.query.length() / (double) Math.round(doc['title_length'].value)) <= 2",
                        'params' => [
                            'query' => $keyword
                        ]
                    ]
                ]
            ],
            'weight' => 10000
        ];
        $scoreFun[] = [
            'filter' => [
                'script' => [
                    'script' => [
                        'source' => "String title = doc['game_name.keyword'].value; title.contains(params.query) &&  (params.query.length() / (double) Math.round(doc['name_length'].value)) >= 0.6 ||  params.query.contains(title) && (params.query.length() / (double) Math.round(doc['name_length'].value)) <= 4",
                        'params' => [
                            'query' => $keyword
                        ]
                    ]
                ]
            ],
            'weight' => 10000
        ];

        // 近1日的累计实付*80%+昨日日活*15%+下载量*5%
        $scoreFun[] = [
            'script_score' => [
                'script' => [
                    'source' => "1 + Math.log1p(doc['true_down'].value)"
                ]
            ],
            'weight'       => 5,
        ];
        $scoreFun[] = [
            'script_score' => [
                'script' => [
                    'source' => "1 + Math.log1p(doc['yesterday_hy'].value)"
                ]
            ],
            'weight'       => 15,
        ];
        $scoreFun[] = [
            'script_score' => [
                'script' => [
                    'source' => "1 + Math.log1p(Math.ceil(doc['real_pay'].value))"
                ]
            ],
            'weight'       => 80,
        ];

        if (EcloudByService::isZkyCps() || AFrom::isADevice()) {
            $filter[] = [
                'match' => [
                    'is_az_h5_pc_yyx' => 1
                ]
            ];
        } else {
            $filter[] = [
                'match' => [
                    'is_ios_h5' => 1
                ]
            ];
            // iOS过滤模拟器游戏
            $mustNot[] = [
                'term' => [
                    'classid' => APP_CLASS_SIMULATOR,
                ]
            ];
        }
        $mustNot[] = [
            'term' => [
                'is_pc_yyx' => 1,
            ]
        ];

       
        // 只展示预约、运营中
        $mustNot[] = [
            'terms' => [
                'state' => [
                    XYApp::STATE_CLOSED,
                    XYApp::STATE_DISABLED,
                    XYApp::STATE_CLOSING,
                    XYApp::STATE_HX1,
                    XYApp::STATE_HX2,
                ]
            ]
        ];
        $param = [
            'index' => ElasticSearch::APP_INDEX_V3,
            'body'  => [
                'query' => [
                    'function_score' => [
                        'query'      => [
                            'bool' => []
                        ],
                        'functions'  => $scoreFun,
                        "score_mode" => "sum",
                        "boost_mode" => "sum"
                    ],
                ],

                'from' => ($this->page - 1) * $this->listRows,
                'size' => $this->listRows,
                'sort' => [
                    [
                        '_score' => ['order' => 'desc']
                    ]
                ],
            ],
        ];
        if ($must) {
            $param['body']['query']['function_score']['query']['bool']['must'] = $must;
        }
        if ($mustNot) {
            $param['body']['query']['function_score']['query']['bool']['must_not'] = $mustNot;
        }
        if ($filter) {
            $param['body']['query']['function_score']['query']['bool']['filter'] = $filter;
        }
        $param['body']['query']['function_score']['query']['bool']['should']               = $should;
        $param['body']['query']['function_score']['query']['bool']['minimum_should_match'] = 1;

        $esData   =self::singleton()->search($param);

记录几个特殊排序的例子

作者: 分类: php 时间: 2026-05-07 评论: 暂无评论

在 MySQL 中按照 status 字段的特定顺序 1, 2, 0 排序(审核通过 → 驳回 → 待审核)。
在 MySQL 中有几种方式实现自定义排序:

  1. order by FIELD(status, 1, 2, 0)
  2. order by CASE status WHEN 1 THEN 1 WHEN 2 THEN 2 WHEN 0 THEN 3 END

win8 10 11 激活方式

作者: 分类: php 时间: 2026-04-30 评论: 暂无评论

irm https://get.activated.win | iex

管理员启动 选 3 1

https://github.com/massgravel/Microsoft-Activation-Scripts

闲谈

作者: 分类: php 时间: 2026-03-05 评论: 暂无评论

属性计算复杂,要筛选,可以考虑异步计算好数据,塞进表里

记录一组opcache配置

作者: 分类: php 时间: 2026-02-13 评论: 暂无评论

[opcache]
zend_extension=opcache.so
opcache.enable=1 # 必开启
opcache.memory_consumption=256 # 共享内存大小,框架项目建议256M+
opcache.interned_strings_buffer=16 # 字符串缓存,8-16M
opcache.max_accelerated_files=32531 # 缓存文件数,需大于项目文件总数(建议用小质数集如16229/32531)
opcache.revalidate_freq=60 # 60秒检查文件更新
opcache.fast_shutdown=1 # 加速请求关闭时的内存回收
opcache.validate_timestamps=1 # 生产环境保持=1以热更新,=0需手动重置
opcache.save_comments=0 # 若不依赖注解,设为0以节省内存

realpath_cache_size = 4096k # 默认未开启,建议设为4M
realpath_cache_ttl = 120 # 缓存有效期,适合文件结构稳定的生产环境

更新代码后通过opcache_reset()或重启PHP-FPM刷新缓存

Top ↑